Secure PHP Programming

Long before a website goes live, you need to take its online security into consideration — to be ready for the attackers even before they might gain access. This three-part article series will warn you of what to watch out for, particularly when configuring PHP, and help you to secure your website. It is excerpted from chapter 21 of the book Beginning PHP and Oracle: From Novice to Professional, written by W. Jason Gilmore and Bob Bryla (Apress; ISBN: 1590597702).

Any Web site can be thought of as a castle under constant attack by a sea of barbarians. And as the history of both conventional and information warfare shows, often the attackers’ victory isn’t entirely dependent upon their degree of skill or cunning, but rather on an oversight by the defenders. As keepers of the electronic kingdom, you’re faced with no small number of potential ingresses from which havoc can be wrought, perhaps most notably the following:

Software vulnerabilities: Web applications are constructed from numerous technologies, typically a database server, a Web server, and one or more programming languages, all of which could be running on one or more operating systems. Therefore, it’s crucial to constantly keep abreast of exposed vulnerabilities and take the steps necessary to patch the problem before someone takes advantage of it.

User input: Exploiting ways in which user input is processed is perhaps the easiest way to cause serious damage to your data and application, an assertion backed up by the numerous reports of attacks launched on high-profile Web sites in this manner. Manipulation of data passed via Web forms, URL parameters, cookies, and other readily accessible routes enables attackers to strike the very heart of your application logic.

Poorly protected data: Data is the lifeblood of your company; lose it at your own risk. All too often, database and Web accounts are left unlocked or protected by questionable passwords. Or access to Web-based administration applications is available through an easily identifiable URL. These sorts of security gaffes are unacceptable, particularly because they are so easily resolved.

Because each scenario poses significant risk to the integrity of your application, all must be thoroughly investigated and handled accordingly. In this chapter, we review many of the steps you can take to hedge against and even eliminate these dangers.

{mospagebreak title=Configuring PHP Securely}

PHP offers a number of configuration parameters that are intended to greatly increase its level of security awareness. This section introduces many of the most relevant options.

Safe Mode

If you’re running a version of PHP earlier than PHP 6, safe mode will be of particular interest if you’re running PHP in a shared-server environment. When enabled, safe mode always verifies that the executing script’s owner matches the owner of the file that the script is attempting to open. This prevents the unintended execution, review, and modification of files not owned by the executing user, provided that the file privileges are also properly configured to prevent modification. Enabling safe mode also has other significant effects on PHP’s behavior, in addition to diminishing, or even disabling, the capabilities of numerous standard PHP functions. These effects and the numerous safe mode–related parameters that comprise this feature are discussed in this section.

Caution  As of version 6, safe mode is no longer available. See Chapter 2 for more information.

safe_mode = On | Off

Scope: PHP_INI_SYSTEM ; Default value: Off

Enabling the safe_mode directive places restrictions on several potentially dangerous language features when using PHP in a shared environment. You can enable safe_mode by setting it to the Boolean value of On , or disable it by setting it to Off . Its restriction scheme is based on comparing the UID (user ID) of the executing script and the UID of the file that the script is attempting to access. If the UIDs are the same, the script can execute; otherwise, the script fails.

Specifically, when safe mode is enabled, several restrictions come into effect:

  1. Use of all input/output functions (e.g., fopen() , file() , and require() ) is restricted to files that have the same owner as the script that is calling these functions. For example, assuming that safe mode is enabled, if a script owned by Mary calls fopen() and attempts to open a file owned by John, it will fail. However, if Mary owns both the script calling fopen() and the file called by fopen() , the attempt will be successful.
  2. Attempts by a user to create a new file will be restricted to creating the file in a directory owned by the user.
  3. Attempts to execute scripts via functions such as popen() , system() , or exec() are only possible when the script resides in the directory specified by the safe_mode_exec_dir configuration directive. This directive is discussed later in this section.
  4. HTTP authentication is further strengthened because the UID of the owner of the authentication script is prepended to the authentication realm. Furthermore, the PHP_AUTH variables are not set when safe mode is enabled.
  5. If using the MySQL database server, the username used to connect to a MySQL server must be the same as the username of the owner of the file calling mysql_connect() .

The following is a complete list of functions, variables, and configuration directives that are affected when the safe_mode directive is enabled:   



backticks()and the backtick operator







































safe_mode_gid = On | Off

Scope: PHP_INI_SYSTEM ; Default value: 0ff

This directive changes safe mode’s behavior from verifying UIDs before execution to verifying group IDs. For example, if Mary and John are in the same user group, Mary’s scripts can call fopen() on John’s files.

safe_mode_include_dir = string

Scope: PHP_INI_SYSTEM ; Default value: NULL

You can use safe_mode_include_dir to designate various paths in which safe mode will be ignored if it’s enabled. For instance, you might use this function to specify a directory containing various templates that might be incorporated into several user Web sites. You can specify multiple directories by separating each with a colon on Unix-based systems, and a semicolon on Windows.

Note that specifying a particular path without a trailing slash will cause all directories falling under that path to also be ignored by the safe mode setting. For example, setting this directive to /home/configuration means that /home/configuration/templates/ and /home/configuration/passwords/ are also exempt from safe mode restrictions. Therefore, if you’d like to exclude just a single directory or set of directories from the safe mode settings, be sure to conclude each with the trailing slash.

safe_mode_allowed_env_vars = string

Scope: PHP_INI_SYSTEM ; Default value: "PHP_"

When safe mode is enabled, you can use this directive to allow certain environment variables to be modified by the executing user’s script. You can allow multiple variables to be modified by separating each with a comma.

safe_mode_exec_dir = string

Scope: PHP_INI_SYSTEM ; Default value: NULL

This directive specifies the directories in which any system programs reside that can be executed by functions such as system() , exec() , or passthru() . Safe mode must be enabled for this to work. One odd aspect of this directive is that the forward slash (/) must be used as the directory separator on all operating systems, Windows included.

safe_mode_protected_env_vars = string

Scope: PHP_INI_SYSTEM ; Default value: LD_LIBRARY_PATH

This directive protects certain environment variables from being changed with the putenv() function. By default, the variable LD_LIBRARY_PATH is protected because of the unintended consequences that may arise if this is changed at run time. Consult your search engine or Linux manual for more information about this environment variable. Note that any variables declared in this section will override anything declared by the safe_mode_allowed_env_vars directive.

{mospagebreak title=Other Security-Related Configuration Parameters}

This section introduces several other configuration parameters that play an important role in better securing your PHP installation.

disable_functions = string

Scope: PHP_INI_SYSTEM ; Default value: NULL

For some, enabling safe mode might seem a tad overbearing. Instead, you might want to just disable a few functions. You can set disable_functions equal to a comma-delimited list of function names that you want to disable. Suppose that you want to disable just the fopen() , popen() , and file() functions. Set this directive like so:

disable_functions = fopen,popen,file

disable_classes = string

Scope: PHP_INI_SYSTEM ; Default value: NULL

Given the new functionality offered by PHP’s embrace of the object-oriented paradigm, it likely won’t be too long before you’re using large sets of class libraries. However, there may be certain classes found within these libraries that you’d rather not make available. You can prevent the use of these classes with the disable_classes directive. For example, suppose you want to completely disable the use of two classes, named administrator and janitor :

disable_classes = "administrator, janitor"

display_errors = On | Off

Scope: PHP_INI_ALL ; Default value: On

When developing applications, it’s useful to be immediately notified of any errors that occur during script execution. PHP will accommodate this need by outputting error information to the browser window. However, this information could possibly be used to reveal potentially damaging details about your server configuration or application. Therefore, when the application moves to a production environment, be sure to disable this directive. You can, of course, continue reviewing these error messages by saving them to a log file or using some other logging mechanism. See Chapter 8 for more information about PHP’s logging features.

doc_root = string

Scope: PHP_INI_SYSTEM ; Default value: NULL

This directive can be set to a path that specifies the root directory from which PHP files will be served. If the doc_root directive is set to nothing (empty), it is ignored, and the PHP scripts are executed exactly as the URL specifies.

max_execution_time = integer

Scope: PHP_INI_ALL ; Default value: 30

This directive specifies how many seconds a script can execute before being terminated. This can be useful to prevent users’ scripts from consuming too much CPU time. If max_execution_time is set to 0 , no time limit will be set.

memory_limit = integer

Scope: PHP_INI_ALL ; Default value: 8M

This directive specifies, in megabytes, how much memory a script can use. Note that you cannot specify this value in terms other than megabytes, and that you must always follow the number with an M . This directive is only applicable if –enable-memory-limit is enabled when you configure PHP.

open_basedir = string

Scope: PHP_INI_SYSTEM ; Default value: NULL

PHP’s open_basedir directive can establish a base directory to which all file operations will be restricted, much like Apache’s DocumentRoot directive. This prevents users from entering otherwise restricted areas of the server. For example, suppose all Web material is located within the directory /home/www . To prevent users from viewing and potentially manipulating files such as /etc/passwd via a few simple PHP commands, consider setting open_basedir like so:

open_basedir = "/home/www/"

sql.safe_mode = integer

Scope: PHP_INI_SYSTEM ; Default value: 0

When enabled, sql.safe_mode ignores all information passed to mysql_connect() and mysql_ pconnect() , instead using localhost as the target host. The user under which PHP is running is used as the username (quite likely the Apache daemon user), and no password is used. Note that this directive has nothing to do with the safe mode feature found in versions of PHP earlier than 6.0; their only similarity is the name.

user_dir = string

Scope: PHP_INI_SYSTEM ; Default value: NULL

This directive specifies the name of the directory in a user’s home directory where PHP scripts must be placed in order to be executed. For example, if user_dir is set to scripts and user Johnny wants to execute somescript.php , Johnny must create a directory named scripts in his home directory and place somescript.php in it. This script can then be accessed via the URL ~johnny/scripts/somescript.php . This directive is typically used in conjunction with Apache’s UserDir configuration directive.

{mospagebreak title=Hiding Configuration Details}

Many programmers prefer to wear their decision to deploy open source software as a badge for the world to see. However, it’s important to realize that every piece of information you release about your project may provide an attacker with vital clues that can ultimately be used to penetrate your server. That said, consider an alternative approach of letting your application stand on its own merits while keeping quiet about the technical details whenever possible. Although obfuscation is only a part of the total security picture, it’s nonetheless a strategy that should always be kept in mind.

Hiding Apache

Apache outputs a server signature included within all document requests and within server-generated documents (e.g., a 500 Internal Server Error document). Two configuration directives are responsible for controlling this signature: ServerSignature and ServerTokens .

Apache’s ServerSignature Directive

The ServerSignature directive is responsible for the insertion of that single line of output pertaining to Apache’s server version, server name (set via the ServerName directive), port, and compiled-in modules. When enabled and working in conjunction with the ServerTokens directive (introduced next), it’s capable of displaying output like this:

Apache/2.0.59 (Unix) DAV/2 PHP/6.0.0-dev Server at Port 80

Chances are you would rather keep such information to yourself. Therefore, consider disabling this directive by setting it to Off .

Apache’s ServerTokens Directive

The ServerTokens directive determines which degree of server details is provided if the ServerSignature directive is enabled. Six options are available: Full , Major , Minimal , Minor , OS , and Prod . An example of each is given in Table 21-1.

Table 21-1. Options for the ServerTokens Directive

Option Example
Full Apache/2.0.59 (Unix) DAV/2 PHP/6.0.0-dev
Major Apache/2
Minimal Apache/2.0.59
Minor Apache/2.0
OS Apache/2.0.59 (Unix)
Prod Apache

Although this directive is moot if ServerSignature is disabled, if for some reason ServerSignature must be enabled, consider setting the directive to Prod .

Please check back next week for the continuation of the series.

Google+ Comments

Google+ Comments