If only you and people you trust can log into your web server, you don't need to worry about file permissions for files created by your PHP programs. However, most web sites are hosted on ISP's machines, and there's a risk that untrusted people will try to read files that your PHP program creates. There are a number of techniques that you can use to deal with file permissions issues.
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 $fp = fopen("/tmp/myfile", "w");
By default, the fopen( ) function attempts to create a file with permission 0666 (rw-rw-rw-). 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.
With PHP's built-in session support, session information is stored in files in the /tmp directory. 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.
This means that session files can be read by any PHP script on the server, as all PHP scripts run with the same web server ID. 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 /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.
For the most secure session variables possible, create your own session store (e.g., in a database). Details for creating a session store are given in Chapter 7.
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. As with session stores, 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 Squid 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.
Many ISPs have scripts from several users running on one web server. Since all the users who share such a server run their PHP scripts as the same user, one script can read another's data files. Safe mode is an attempt to address this and other problems caused by shared servers. If you're not sharing your server with other users that you don't trust, you don't need to worry about safe mode at all.
When enabled through the safe_mode directive in your php.ini file, or on a per-directory or per-virtual host basis in your httpd.conf file, the following restrictions are applied to PHP scripts:
PHP looks at the owner of the running script and pretends[6] to run as that user.
[6]PHP can't switch the user ID via a setuid( ) call because that would require the web server to run as root and on most operating systems it would be impossible to switch back.
Any file operation (through functions such as fopen( ), copy( ), rename( ), move( ), unlink( ), chmod( ), chown( ), chgrp( ), mkdir( ), file( ), flock( ), rmdir( ), and dir( )) checks to see if the affected file or directory is owned by the same user as the PHP script.
If safe_mode_gid is enabled in your php.ini or httpd.conf file, only the group ID needs to match.
include and require are subject to the two previous restrictions, with the exception of includes and requires of files located in the designated safe_mode_include_dir in your php.ini or httpd.conf file.
Any system call (through functions such as system( ), exec( ), passthru( ), and popen( )) can access only executables located in the designated safe_mode_exec_dir in your php.ini or httpd.conf file.
If safe_mode_protected_env_vars is set in your php.ini or httpd.conf file, scripts are unable to overwrite the environment variables listed there.
If a prefix is set in safe_mode_allowed_env_vars in your php.ini or httpd.conf file, scripts can manipulate only environment variables starting with that prefix.
When using HTTP authentication, the numerical user ID of the current PHP script is appended to the realm[7] string to prevent cross-script password sniffing, and the authorization header in the getallheaders( ) and phpinfo( ) output is hidden.
[7]This realm-mangling took a little vacation in PHP 4.0.x but is back in PHP 4.1 and later.
The functions set_time_limit( ), dl( ), and shell_exec( ) are disabled, as is the backtick (``) operator.
To configure safe_mode and the various related settings, you can set the serverwide default in your php.ini file like this:
safe_mode = On safe_mode_include_dir = /usr/local/php/include safe_mode_exec_dir = /usr/local/php/bin safe_mode_gid = On safe_mode_allowed_env_vars = PHP_ safe_mode_protected_env_vars = LD_LIBRARY_PATH
Alternately, you can set these from your httpd.conf file using the php_admin_value directive. Remember, these are system-level settings, and they cannot be set in your .htaccess file.
<VirtualHost 1.2.3.4> ServerName domainA.com DocumentRoot /web/sites/domainA php_admin_value safe_mode On php_admin_value safe_mode_include_dir /usr/local/php/include php_admin_value safe_mode_exec_dir /usr/local/php/bin </VirtualHost>
Copyright © 2003 O'Reilly & Associates. All rights reserved.