Fortunately, the PHP designers considered this situation, and created "safe mode" - a setting that can be toggled in the php.ini file, which, when enabled, applies various weak lockdowns to the language. For example, by default safe mode blocks the dl() function, as it could potentially be used by attackers to load an unsafe extension for execution.
Before continuing, you need to know that safe mode is really not that safe at all. In fact, it's a source of much confusion whereby people think that they are somehow safe from security threats because they have safe mode enabled, and that's simply not true. As a result, safe mode has been removed from PHP 6 onwards.
By default, PHP running in safe mode will only work with files that are owned by the same person who owns the script that is being run - the user ID (UID) of the owner of the script must match the UID of the owner of the file being read. This includes files being read through fopen(), and even files being read through an include call. In addition, there are XYZ settings in your php.ini file that are likely to be of help if you are trying to secure your PHP environment:
safe_mode_include_dir: This defines a directory you consider safe on your computer, where all files can be worked with regardless of their ownership. Files read from this directory do not have their UID checked against the owner of the script
safe_mode_exec_dir: This defines a directory from which you want PHP to be able to execute programs while running in safe mode. If this is not set, all calls to exec() will fail.
safe_mode_allowed_env_vars: This defines a list of environment variables that the user will be allowed to change. If this is not set, all variables can be edited, which is not likely to be a good thing if abused.
open_basedir: This setting allows you to limit the location from where files can be read, thereby stopping people from reading in any files they please. This is a tricky setting to get right, and is discussed in more depth below.
disable_functions: This setting does precisely what you would expect it to - provide it with a list of functions you do not want to be used, and it will automatically stop scripts from using them. Specify multiple functions with commas, for example: readfile,exec,fopen.
disable_classes: This takes a list of classes you do not want people to create objects from, and stops them being created, as you would expect. As with disable_functions, use commas to separate multiple class names.
The settings are generally easy to grasp, as you can see, however open_basedir is a little more complicated than it first seems. For example, open_basedir will work regardless of whether safe mode is enabled, whereas the others only kick in when PHP is operating in safe mode. Secondly, the directories you pass in to this directive, separated by commas, are considered prefixes by default. For example, /home/paul will allow files in /home/paul to be loaded, but also in /home/paul_the_hacker, etc. To clarify a particularly directory exactly, use your directory delimiter - / in Unix, and \ in Windows. For example: /home/paul/ would only match the directory /home/paul.
Finally, note that this directive resolves all links. For example, if file /home/paul/passwd is symlinked to /etc/passwd, and open_basedir has been used to restrict file inclusion to /home/paul/, including /home/paul/passwd would fail - PHP would detect that it linked to a file stored in /etc, outside of the open_basedir path, and prevent the call from continuing.
Next chapter: Protecting your data >>
Previous chapter: Understanding the concerns
Home: Table of Contents