Team LiB
Previous Section Next Section

3.1. Installation

In this section, I will present the installation and configuration procedures for two different options: using PHP as a module and using it as a CGI. Using PHP as a module is suitable for systems that are dedicated to a single purpose or for sites run by trusted groups of administrators and developers. Using PHP as a CGI (possibly with an execution wrapper) is a better option when users cannot be fully trusted, in spite of its worse performance. (Chapter 6 discusses running PHP over FastCGI which is an alternative approach that can, in some circumstances, provide the speed of the module combined with the privilege separation of a CGI.) To begin with the installation process, download the PHP source code from http://www.php.net.

3.1.1. Using PHP as a Module

When PHP is installed as a module, it becomes a part of Apache and performs all operations as the Apache user (usually httpd). The configuration process is similar to that of Apache itself. You need to prepare PHP source code for compilation by calling the configure script (in the directory where you unpacked the distribution), at a minimum letting it know where Apache's apxs tool resides. The apxs tool is used as the interface between Apache and third-party modules:

$ ./configure --with-apxs=/usr/local/apache/bin/apxs
$ make
# make install

Replace --with-apxs with --with-apxs2 if you are running Apache 2. If you plan to use PHP only from within the web server, it may be useful to put the installation together with Apache. Use the --prefix configuration parameter for that:

$ ./configure \
> --with-apxs=/usr/local/apache/bin/apxs \ 
> --prefix=/usr/local/apache/php

In addition to making PHP work with Apache, a command-line version of PHP will be compiled and copied to /usr/local/apache/php/bin/php. The command-line version is useful if you want to use PHP for general scripting, unrelated to web servers.

The following configuration data makes Apache load PHP when it starts and allows Apache to identify which pages contain PHP code:

# Load the PHP module (the module is in
# subdirectory modules/ in Apache 2)
LoadModule php5_module libexec/libphp5.so
# Activate the module (not needed with Apache 2)
AddModule mod_php5.c
   
# Associate file extensions with PHP
AddHandler application/x-httpd-php .php
AddHandler application/x-httpd-php .php3
AddHandler application/x-httpd-php .inc
AddHandler application/x-httpd-php .class
AddHandler application/x-httpd-php .module

I choose to associate several extensions with the PHP module. One of the extensions (.php3) is there for backward compatibility. Java class files end in .class but there is little chance of clash because these files should never be accessed directly by Apache. The others are there to increase security. Many developers use extensions other than .php for their PHP code. These files are not meant to be accessed directly but through an include() statement. Unfortunately, these files are often stored under the web server tree for convenience and anyone who knows their names can request them from the web server. This often leads to a security problem. (This issue is discussed in more detail in Chapter 10 and Chapter 11.)

Next, update the DirectoryIndex directive:

DirectoryIndex index.html index.php

Finally, place a version of php.ini in /usr/local/apache/php/lib/. A frequent installation error occurs when the configuration file is placed at a wrong location, where it fails to have any effect on the PHP engine. To make sure a configuration file is active, create a page with a single call to the phpinfo( ) function and compare the output with the settings configured in your php.ini file.

3.1.2. Using PHP as a CGI

Compiling PHP as a CGI is similar to compiling it for the situation where you are going to use it as a module. This mode of operation is the default for PHP, so there is no need to specify an option on the configure line. There are two ways to configure and compile PHP depending on the approach you want to use to invoke PHP scripts from Apache.

One approach is to treat PHP scripts like other CGI scripts, in which case the execution will be carried out through the operating system. The same rules as for other CGI scripts apply: the file must be marked as executable, and CGI execution must be enabled with an appropriate ExecCGI option in the configuration. To compile PHP for this approach, configure it with the --enable-discard-path option:

$ ./configure \
> --enable-discard-path \
> --prefix=/usr/local/apache/php
$ make
# make install

The operating system must have a way of determining how to execute the script. Some systems use file extensions for this purpose. On most Unix systems, the first line, called the shebang line, in the script must tell the system how to execute it. Here's a sample script that includes such a line:

#!/usr/local/apache/php/bin/php
<? echo "Hello world"; ?>

This method of execution is not popular. When PHP is operating as an Apache module, PHP scripts do not require the shebang line at the top. Migrating from a module to CGI operation, therefore, requires modifying every script. Not only is that time consuming but also confusing for programmers.

The second approach to running PHP as a CGI is Apache-specific and relies on Apache's ability to have a CGI script post-process static files. First, configure, compile, and install PHP, this time specifying the --enable-force-cgi-redirect option:

$ ./configure \
> --enable-force-cgi-redirect \
> --prefix=/usr/local/apache/php
$ make
# make install

Place a copy of the PHP interpreter (/usr/local/apache/php/bin/php) into the web server's cgi-bin/ directory. Configure Apache to use the interpreter to post-process all PHP files. In the example below, I am using one extension (.php), but you can add more by adding multiple AddHandler directives (as shown in Section 3.1.1):

Action application/x-httpd-php /cgi-bin/php
AddHandler application/x-httpd-php .php

I have used the same MIME type (application/x-httpd-php) as before, when configuring PHP to work as a module. This is not necessary but it makes it easier to switch from PHP working as a module to PHP working as a CGI. Any name (e.g., php-script) can be used provided it is used in both directives. If you do that, you can have PHP working as a module and as a script at the same time without a conflict.

Placing an interpreter (of any kind) into a cgi-bin/ directory can be dangerous. If this directory is public, then anyone can invoke the interpreter directly and essentially ask it to process any file on disk as a script. This would result in an information leak or command execution vulnerability. Unfortunately, there is no other way since this is how Apache's Action execution mechanism works. However, a defense against this type of attack is built into PHP, and that's what the --enable-force-cgi-redirect switch we used to compile PHP is for. With this defense enabled, attempts to access the PHP interpreter directly will always fail. I recommend that you test the protection works by attempting to invoke the interpreter directly yourself. The configure script silently ignores unrecognized directives, so the system can be open to attack if you make a typing error when specifying the --enable-force-cgi-redirect option.

To ensure no one can exploit the PHP interpreter by calling it directly, create a separate folder, for example php-cgi-bin/, put only the interpreter there, and deny all access to it using Deny from all. Network access controls are not applied to internal redirections (which is how the Action directive works), so PHP will continue to work but all attack attempts will fail.


3.1.3. Choosing Modules

PHP has its own extension mechanism that breaks functionality into modules, and it equally applies when it is running as an Apache module or as a CGI. As was the case with Apache, some PHP modules are more dangerous than others. Looking at the configure script, it is not easy to tell which modules are loaded by default. The command line and CGI versions of PHP can be invoked with a -m switch to produce a list of compiled-in modules (the output in the example below is from PHP 5.0.2):

$ ./php -m
[PHP Modules]
ctype
iconv
pcre
posix
session
SPL
SQLite
standard
tokenizer
xml
   
[Zend Modules]

If you have PHP running as an Apache module, you must run the following simple script as a web page, which will provide a similar output:

<pre>
<?
$extension_list = get_loaded_extensions(  );
foreach($extension_list as $id => $extension) {
    echo($id . ". " . $extension . "\n");
}
?>
</pre>

For the purpose of our discussion, the list of default modules in the PHP 4.x branch is practically identical. From a security point of view, only the posix module is of interest. According to the documentation (http://www.php.net/manual/en/ref.posix.php), it can be used to access sensitive information. I have seen PHP-based exploit scripts use POSIX calls for reconnaissance. To disable this module, use the --disable-posix switch when configuring PHP for compilation.

In your job as system administrator, you will likely receive requests from your users to add various PHP modules to the installation (a wealth of modules is one of PHP's strengths). You should evaluate the impact of a new PHP module every time you make a change to the configuration.

    Team LiB
    Previous Section Next Section