If only you and people you trust can log in to your web server, you don’t need to worry about file permissions for files used by or created by your PHP programs. However, most websites are hosted on ISP’s machines, and there’s a risk that non trusted people can read files that your PHP program creates. There are a number of techniques that you can use to deal with file permissions issues.
Restrict Filesystem Access to a Specific Directory You can set the
open_basedir option to restrict access from your PHP scripts to a specific directory. If
open_basedir is set in your
php.ini, PHP limits filesystem and I/O functions so that they can operate only within that directory or any of its subdirectories. For example:
open_basedir = /some/path
With this configuration in effect, the following function calls succeed:
But these generate runtime errors:
$fp = fopen("/some/other/file.exe", 'r'); $dp = opendir("/some/path/../other/file.exe");
Of course, one web server can run many applications, and each application typically stores files in its own directory. You can configure
open_basedir on a per-virtual host basis in your httpd.conf file like this:
<VirtualHost 188.8.131.52> ServerName domainA.com DocumentRoot /web/sites/domainA php_admin_value open_basedir /web/sites/domainA </VirtualHost>
Similarly, you can configure it per directory or per URL in
# by directory <Directory /home/httpd/html/app1> php_admin_value open_basedir /home/httpd/html/app1 </Directory> # by URL <Location /app2> php_admin_value open_basedir /home/httpd/html/app2 </Location>
open_basedir directory can be set only in the
httpd.conf file, not in
.htaccess files, and you must use
php_admin_value to set it.
Get It Right the First Time
Do not create a file and then change its permissions. This creates a race condition, where a lucky user can open the file once it’s created but before it’s locked down. Instead, use the
umask() function to strip off unnecessary permissions. For example:
umask(077); // disable ---rwxrwx $fh = fopen("/tmp/myfile", 'w');
By default, the
fopen() function attempts to create a file with permission
0666 (rw-rwrw-). Calling
umask() first disables the group and other bits, leaving only
0600 (rw-------). Now, when fopen() is called, the file is created with those permissions.
Don’t Use Files
Because all scripts running on a machine run as the same user, a file that one script creates can be read by another, regardless of which user wrote the script. All a script needs to know to read a file is the name of that file.
There is no way to change this, so the best solution is to not use files to store data that should be protected; the most secure place to store data is in a database.
A complex workaround is to run a separate Apache daemon for each user. If you add a reverse proxy such as haproxy in front of the pool of Apache instances, you may be able to serve 100+ users on a single machine. Few sites do this, however, because the complexity and cost are much greater than those for the typical situation, where one Apache daemon can serve web pages for thousands of users.
With PHP’s built-in session support, session information is stored in files. Each file is named
/tmp/sess_id, where id is the name of the session and is owned by the web server user ID, usually nobody.
Because all PHP scripts run as the same user through the web server, this means that any PHP script hosted on a server can read any session files for any other PHP site. In situations where your PHP code is stored on an ISP’s server that is shared with other users’ PHP scripts, variables you store in your sessions are visible to other PHP scripts.
Even worse, other users on the server can create files in the session directory
/tmp. There’s nothing preventing a user from creating a fake session file that has any variables and values he wants in it. The user can then have the browser send your script a cookie containing the name of the faked session, and your script will happily load the variables stored in the fake session file.
One workaround is to ask your service provider to configure their server to place your session files in your own directory. Typically, this means that your VirtualHost block in the Apache
httpd.conf file will contain:
php_value session.save_path /some/path
If you have .htaccess capabilities on your server and Apache is configured to let you override options, you can make the change yourself.
Concealing PHP Libraries
Many a hacker has learned of weaknesses by downloading include files or data that are stored alongside HTML and PHP files in the web server’s document root. To prevent this from happening to you, all you need to do is store code libraries and data outside the server’s document root.
For example, if the document root is
/home/httpd/html, everything below that directory can be downloaded through a URL. It is a simple matter to put your library code, configuration files, logfiles, and other data outside that directory (e.g., in
/usr/local/lib/myapp). This doesn’t prevent other users on the web server from accessing those files but it does prevent the files from being downloaded by remote users.
If you must store these auxiliary files in your document root, you should configure the web server to deny requests for those files. For example, this tells Apache to deny requests for any file with the .inc extension, a common extension for PHP include files:
<Files ~ "\.inc$"> Order allow,deny Deny from all </Files>
A better and more preferred way to prevent downloading of PHP source files is to always use the .php extension.
If you store code libraries in a different directory from the PHP pages that use them, you’ll need to tell PHP where the libraries are. Either give a path to the code in each
require(), or change
include_path = ".:/usr/local/php:/usr/local/lib/myapp";
Here is the list of of Article in this Series:
- PHP – Securing your Web Application : Introduction
- PHP – Securing your Web Application : Filter Input
- PHP – Securing your Web Application : Cross-Site Scripting
- PHP – Securing your Web Application : SQL Injection
- PHP – Securing your Web Application : Escape Output
- PHP – Securing your Web Application : Filenames
- PHP – Securing your Web Application : Session Fixation
- PHP – Securing your Web Application : File Uploads
- PHP – Securing your Web Application : File Access
- PHP – Securing your Web Application : PHP Code
- PHP – Securing your Web Application : Shell Commands
- PHP – Securing your Web Application : More information and Summary
Please share the article if you like let your friends learn PHP Security. Please comment any suggestion or queries.
Thanks Kevin Tatroe, Peter MacIntyre and Rasmus Lerdorf. Special Thanks to O’Relly.