I have a php site with a web root directory /var/www/html/limesurvey/. Let's say this maps to the URL https://mylimesurveysite.com/.
The default runtimePath where logs are saved is /var/www/html/limesurvey/tmp/runtime/. If I wanted to download a log file, I could visit the URL https://mylimesurveysite.com/tmp/runtime/application.log and my browser would automatically download the log file. I've tested this.
If I set the runtimePath to /var/limesurvey_runtime/, are my log files in this directory still accessible to the internet somehow?
I tried to visit https://mylimesurveysite.com/../../../limesurvey_runtime/application.log and it doesn't seem like the log file can be accessed this way. So it seems URLs aren't evaluated like programming language paths.
TLDR; Browsers and webservers work together to try to ensure that only designated resources in the web root are accessible. It would be a major security violation if a web client could access arbitrary files on the server.
First, the browser automatically canonicalizes pathnames in URLs. This means that any XXX/.. pairs are automatically removed, so if you have a URL with /a/b/../c/d it's converted to /a/c/d. Next, any leading ../ are removed, so the URL https://mylimesurveysite.com/../../../limesurvey_runtime/application.log is converted to https://mylimesurveysite.com/limesurvey_runtime/application.log.
But we can't depend on browsers for security, because hackers can bypass browsers and write scripts that send arbitrary paths to the server. So servers are normally configured to block any access outside the defined web root directory. There's also optional settings to allow accessing directories in user directories, typically with paths beginning with ~username/; this is typically mapped by the server to something like /home/username/public_html/.
In either case, any ../ in the path that would go outside the web root or public_html directory are prohibited, and should result in a 404 Not found error.
If you want to allow access to something outside the web root, the usual way to do it is with a script that fetches files after validating that it's allowed. You may also be able to use symbolic links in the web root that point outside, although this may also be disabled in webserver configurations.
You could try creating a php file in your "public_html" or root web directory that reads that log file. For example in the PHP file you could say:
readfile("/var/www/html/limesurvey/tmp/runtime/application.log");
Related
I have concerns that are similar to what were addressed here. I'm using Composer to install Amazon AWS components to set up a SES (email) service.
According to the Amazon documentation, I need to include autoload.php in order to use the classes that I installed. This means that the autoload.php must be in my web directory (/var/www/html).
I didn't fully understand the answer provided to the SO question I previous mentioned, but it essentially says that the vendor directory should NOT be in the web directory. But if I do this, how will I require the autoload.php file, which is in the /vendor directory?
Overall I am very confused about how I should be properly setting this up. Any help would be appreciated.
Edit: This article also suggests putting the /vendor/ folder in the web directory. Is this the standard? What security risks should I be looking out for? Because there are no index.html files or anything in any of the folders, the directories of all the files that were installed can be seen and accessed freely. Surely this can't be a good thing?
The "web directory" is the directory directly served via HTTP to anyone asking with the right URL. So if anyone thinks there is a folder "/foo" hosted on your domain, and you didn't take precautions, and there is in fact that folder, and it does not contain a file that would be served as the directory index, anyone asking probably would get the directory listing of that folder, listing all files.
Now the difference between such a web hosted folder and the require statement in PHP is that PHP does not use a URL pointing at a publicly accessible HTTP hosted folder, but uses a filesystem path pointing to a file.
And most beginners mix this up: Because PHP at starter level is all about having a bunch of scripts spread around the web directory, which emit a lot of HTML containing links to other scripts, they get the idea that the links in HTML and the file paths in PHP are the same and have to be. This is wrong. They don't have to be the same, they are the same because no better approach has been selected.
So here's how a modern web application is constructed. If you deploy the whole project, the main directory on the server might be called /var/www/projectX. Inside this container are some files like /var/www/projectX/composer.json. Because of this there will also be a directory /var/www/projectX/vendor. Additionally, somewhere would be one PHP script that's being accessed (I delay the info HOW it's being accessed for now), and that location should either be A) /var/www/projectX/script.php or B) /var/www/projectX/public/script.php. Those two scripts want to use Composer provided classes and need to include the autoloading.
Because of the file location, the script in location A needs to run require 'vendor/autoload.php';, and the script in location B needs require '../vendor/autoload.php';. This is simply a matter of using the correct relative path from the script to the autoload file. You could even use an absolute path in both cases: require '/var/www/projectX/vendor/autoload.php'; will also work. The main point here is: It does not matter HOW you require that autoload.php file as long as it gets executed by the script. The path does not affect anything.
Now the HTTP hosting and accessing the scripts. The webserver has at least one directory configured that is being exposed to the outside world as the main directory of the domain. This is called DOCUMENT_ROOT, and it can be ANYWHERE. Now it depends on the configuration of your server which directory is preselected, and if you can change that setting (either by administrating your server on the command line, or by clicking some settings in a GUI).
If your server has the directory /var/www/projectX set as the document root, all the world can access the script in case A as http://example.com/script.php, as well as the script in case B as http://example.com/public/script.php, and also the vendor folder as http://example.com/vendor/.... This is not great, but could be avoided by placing .htaccess files inside or otherwise restrict access.
The better solution is to tell the server to only serve the directory /var/www/projectX/public as document root. This will prevent HTTP access to script A and the vendor folder, and access to script B is done via http://example.com/script.php.
In both cases, both scripts successfully include the autoloading of Composer because the restrictions of HTTP access do not apply to filesystem access.
Bad website hosting allows you only to use the first scenario, with the only accessible directory for you being directly the document root, without a method to change it.
More sophisticated website hosting ís using a fixed subdirectory like public or html or webroot as the document root, allowing you to hide sensitive files from ever being served via HTTP.
The best website hosting allows you to select which subdirectory should be hosted as document root.
In any case, the path pointing from a script to Composers autoload.php is not affected at all.
I have different folders in the site I am making.
What if the user tries to enter that folder, How would I not let them see what's inside?
Or can I redirect them into another page saying that they don't have the permission to access the folder/ invalid url?
I read something about htaccess but I dunno how that one works.
I am currently doing some trick (like adding index.php in the folders with a message saying they don't have permission to access) to every folder.
But it's kind of a pain. And I believe there's an easier method.
It depends on the contents of the folders:
If it contains php or configuration files that are never to be opened directly (or anything else that never needs to be requested directly by the browser), you should not put them in the web-root;
If it contains assets that are included in html but you do not want the visitor to browse the directory, you should configure your web-server so that directory browsing is disabled;
If only certain logged-in users should be able to open certain files, you should handle that in the file itself, not on the directory level.
If you cannot move your directory out of the web-root but nothing in it needs to be accessible by the browser, you can put an .htaccess file in that directory with just the following contents:
deny from all
This is something you should accomplish on a server level.
Basically restraining access to these folders on UNIX (chmod -r) for example will take care of this for you.
Sorry if this is a trivial question.
I am a kind of new to PHP and I'm creating a project from scratch. I need to store my application logs (generated using log4php) as files, and I don't want them to be public.
They are now stored in a subfolder under my PHP application folder, (/myAppFolder/logs) so they are served by Apache.
Where shall I store them, or what shall I do to keep them away from being served as content by Apache?
You can either have them in a directory above the root, or, if you're on shared host/ can't have the files above the root for whatever reason, you can have them in a directory that denies all HTTP access.
So you could have a folder called "secret_files" with a .htaccess file sitting inside:
.htaccess:
deny from all
Which will prevent HTTP access to files/subfolders in that folder.
Somewhere not under the public root!?
This is more a server config question as it depends on your server, but in apache you could use the custom log directives to set the location, so if you have
/www/myapp
Create
/www/log
and put them there instead. You need control over the config to do this so look up your web hosts docs to find out how.
Is there a way to stop users from typing in a url and gaining access to a file in a specific directory but still allow a PHP script to have access to the file to change it or download it?
In other words, I want to stop people from typing in: http://www.mysite.com/securefolder/file1.pdf. Maybe redirect them to a different page or something.
But I do not want to completely lock away the files because I still need to use a PHP script to download and modify the files.
Any help is appreciated,
Thanks
If all you want is a specific setting for a certain file a very simple rule will be all you need -
RewriteEngine on
RewriteRule ^/securefolder/file1.pdf$ access_denied.php
What might be a better idea is to make a rule for the entire secured folder -
RewriteEngine on
RewriteRule ^/securefolder/.*$ access_denied.php
One last (and probably best) way to do this is to create an additional .htaccess inside the secured folder and simply deny all access to it. Place this one line -
deny from all
In all of the solutions, we are only talking about external requests. All your scripts and internal paths to scripts, files, etc... will remain intact and unaffected by the rules you define within the .htaccess files.
Disable direct access to the file on the webserver, and serve the file from a PHP script (some hints on this manual page: http://www.php.net/manual/en/function.readfile.php). Webserver access restictions won't affect PHP, as it is directly accessing the filesystem. Here's a similar question: Secure files for download
If performance is critical, there is plugin for most of the webservers which will help you to serve the file directly (bypassing PHP):
Apache mod_auth_token
Lighttpd mod_secdownload
Nginx secure_download
The ideal approach will depend on whether the PHP script accesses the PDF file locally on disk, or remotely over http.
If the PHP script accesses the file locally on disk, simply place the file outside the root folder of the web site.
If the PHP script access the file remotely over http, here are some options:
Limit access by origin IP
Password protect the resource and serve over https
If the files are on the same server, you don't need to download them in order to serve them. Simply read them from the filesystem and output them directly.
If, however, they're not, and you need a script to be able to download files, and others to be refused, you could password protect the directory.
To then download files using for instance cURL, you can specify the following options:
curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
More information
Password Protecting Your Pages with htaccess
Sending a username and password with PHP cURL
Place your data file outside of the public web space. Read the file using PHP and serve.
There is no reason for the source file to be located within the web host's DocumentRoot unless you want the file to be served publicly.
A PHP script runs as local user and so is able to read the file even outside the scope of Apache (or other) web server.
I'm building a website based on php and i want to ask where to put files that are retrieved with a require statement, so that they can not be accessed from users with their browser.
(for example a php file that connects to my database)
EDIT actually i think the better way is to put them outside the public root because apache tutorial says htaccess will have a slowdown impact. it can be done with adding a ../
for example require("../myFile.php"); (At least this works in my server)
Best regards to all
That depends on the web server configuration. Usually (or at least in all cases I witnessed), you have a document root which cannot be accessed by users with their browser, with in there a folder containing all public material (often called htdocs, httpdocs, public_html or anything of the kind. Often, you can place your PHP include files in that root, and then require them using require("../include_file.php");
However, it depends on the configuration whether PHP can include files outside your public folder. If not, a .htaccess file is your best option.
If you place those files outside the document root of your webserver users cannot access these files with a browser.
If you use apache you can also place these files in a directory to which you do not allow access with a .htaccess file.
And as a last remark, if your files do not generate output, there is no way users can check the contents of the files.
If you mean source code then it is not visible for users, if you want hide folder contents use .htaccess directive Options -Indexes to hide files, if you can access php source your server configuration is wrong and it is not parsing php files.
You normally place them into a directory that is not accessible over the webserver (outside the document or web root). Sometimes called a "private" directory.
You then include/require the file from that path as PHP has still access to the files.
See also:
placing php script outside website root
disable access to included files - For a method if you're not able to place the files in a private directory.
Just make them secure with .htacces!
Here's a very clear tutorial for protecting files with a password. If you don't need direct access to the files per browser, or only your scripts need access, just block them completly by changing the code between
<Files xy>
change this bit here
</Files>
to
Order allow,deny
Deny from all
Then you won't need your htpassword file anymore either!
You need to put these files outside of public-facing folders on your web server. Most (all?) web hosts should have the capability to change the document root of the website.
For example, let's say that all of your files are served from the following directory on your host: /home/username/www/example.com/
This means that anything that resides inside that directory is visible to the internet. If you went to http://example.com/myfile.png it would serve the file at /home/username/www/example.com/myfile.png.
What you want to do is create a new directory called, for example, public which will serve your files, and point the document root there. After you've done that, the request for http://example.com/myfile.png will be served from /home/username/www/example.com/public/myfile.png (note the public directory here). Now, anything else that resides within the example.com directory won't be visible on your website. You can create a new directory called, for example, private where your sensitive include files will be stored.
So say you have two files: index.php, which serves your website, and sensitive.php which contains passwords and things of that nature. You would set those up like this:
/home/username/www/example.com/public/index.php
/home/username/www/example.com/private/sensitive.php
The index.php file is visible to the internet, but sensitive.php is not. To include sensitive.php, you just include the full file path:
require_once("/home/username/www/example/com/private/sensitive.php");
You can also set your application root (the root of your websites files, though not the root of the publicly accessible files) as a define, possibly in a config file somewhere, and use that, e.g.:
require_once(APP_ROOT . "sensitive.php");
If you can't change the document root, then what some frameworks do is use a define to note that the file shouldn't be executed directly. You create a define in any file you want as an entry point to your application, usually just index.php, like so:
if (!defined('SENSITIVE')) {
define('SENSITIVE', 'SENSITIVE');
}
Then, in any sensitive file, you check that it's been set, and exit if it hasn't, since that means the file is being executed directly, and not by your application:
if (!defined('SENSITIVE')) {
die("This file cannot be accessed directly.");
}
Also, make sure that your include files, when publicly accessible (and really, even if not), have a proper extension, such as .php, so that the web server knows to execute them as PHP files, rather than serving them as plain text. Some people use .inc to denote include files, but if the server doesn't recognize them as being handled by PHP, your code will be publicly visible to anyone who cares to look. That's not good! To prevent this, always name your files with a .php extension. If you want to use the .inc style to show your include files, consider using .inc.php instead.