16.5 Using PHP Securely

only for RuBoard - do not distribute or recompile

16.5 Using PHP Securely

PHP is a widely used and loved server-side scripting language for building web pages. Originally called Personal Home Page, and then PHP3, PHP now stands for PHP Hypertext Preprocessor. The web site for PHP development is http://www.php.org/. PHP is an official project of The Apache Foundation.[9]

[9] Some of the information presented in this section is based on Shaun Clowes' presentation at the Blackhat Briefings Asia 2001. Clowes' paper on PHP security, "A Study in Scarlet," can be downloaded from http://www.securereality.com.au/archives/studyinscarlet.txt.

16.5.1 Introduction to PHP

Although originally developed under Unix with the Apache web server, PHP now runs on Unix and Windows and with both Apache and Microsoft's IIS. Some of the key advantages of PHP include:

  • It is easy to use and very fast. Even though PHP scripts are interpreted at runtime, the interpreter is built into the web server. As a result, PHP pages can run significantly faster (more than 10 times faster is not uncommon) than the equivalent Perl/CGI web pages.[10]

    [10] Perl/CGI web pages are slow because a new copy of the Perl interpreter is started each time a page is downloaded. Perl pages that are served using the mod_perl interface can be as fast or faster than PHP pages.

  • Unlike CGI scripts, PHP pages do not need to be made "executable" or placed in special directories to run: if PHP is enabled in the web server, all you need to do is to give an HTML file a .php or .php3 extension and the PHP system will automatically run.

  • The PHP interpreter shows errors directly on the web page, not in a log file.

  • PHP can cache connections to the MySQL database system. As a result, PHP pages that are fed from information in a database can display dramatically faster than database-driven pages using other systems.

  • PHP is extremely powerful. Scripts written in PHP can open files, open network connections, and execute other programs.

All of these factors combine to make PHP very popular.

Here is a simple PHP script:

<html><head><title>PHP Test</title></head> <body> <?php    echo "Hello World!<p>"; ?> </body></html>

Place this script in a file called demo.php and read the page from your web server, and you'll see:

Hello World!

The key mechanism here involves the tags <?php and ? >. When the PHP interpreter starts up, it scans the .php page and looks for these tags. Any text that is not between these tags is sent to the web browser. Any code between these tags is executed in place. This process continues until the entire file is read, at which point the PHP interpreter returns to the Apache web server.

PHP variables look and act a lot like Perl variables. That is, variables begin with dollar signs and are untyped; they switch between being numbers or strings as needed. If a variable occurs within a double-quoted string, the variable is automatically substituted. To see how this works, let's modify the PHP script so that it counts to 5:

<html><head><title>PHP Test</title></head> <body> <?php    for($i=0;$i<5;$i++){      echo "This is line $i<br>";    } ?> </body></html>

Here is the result:

This is line 0 This is line 1 This is line 2 This is line 3 This is line 4

And here is the HTML file that the script actually generated:

<title>PHP Test</title></head> <body> This is line 0<br>This is line 1<br>This is line 2<br>This is line 3<br>This is line  4<br></body></html>

The two key points about this second demonstration are that PHP doesn't require you to declare your variables, and the PHP interpreter really doesn't know much about the HTML that it produces it just shoots it out and lets the browser display it.

16.5.2 Controlling PHP

PHP's behavior is controlled by the PHP initialization file, php.ini. PHP directives can also be placed in the Apache httpd.conf file.

Using the Apache configuration file, many PHP features can be controlled on a directory-by-directory basis. For example, the section shown here, taken from an httpd.conf file, enables the PHP3 safe mode (described later in the chapter in the section "PHP Safe Mode") by default in the directory /htdocs but not in the directory /staffdocs:

<IfModule mod_php3.c>   AddType application/x-httpd-php .php   AddType application/x-httpd-php3 .php3   <Directory /htdocs/>     php3_safe_mode on  </Directory> <Directory /htdocs/>     php3_safe_mode off  </Directory> </IfModule>

16.5.3 Understanding PHP Security Issues

PHP is an incredibly powerful system. Unfortunately, it is also a very lax system: many of the protections available in other scripting environments do not exist in PHP. This can be a great advantage when you are trying to get something out quickly, but it can also create problems for security-sensitive environments.

PHP is also a widely used system. PHP is used on shared web servers run by ISPs. It is also part of the default installation for many single-user Linux installations. As is typically the case with complicated systems, the environment in which you run PHP will determine many of the security concerns that you may need to address. PHP presents a number of challenges because of its vast power:

  • If you have a shared computer that uses PHP for many different users (for example, an ISP that uses PHP on its customer web server), some users may be able to use PHP to access private files belonging to other users.

  • If you have PHP installed on a computer where users are not allowed to run their own programs, your users may be able to use PHP to bypass this restriction.

Many of the potential security problems with PHP arise because it is possible to make changes to the PHP script's runtime environment in ways that may not have been anticipated by the original script programmer or ways that may not be evident to people who review the script after the original programmer leaves. Thus:

  • Programmers can use some relatively obscure PHP behaviors to hide back doors into your system. These back doors might even be hidden from other programmers working on the same project.

  • If you download and run PHP scripts that are commonly available on the Internet, attackers may discover flaws in these scripts and use those flaws to break into your system.

In the following sections, we look at specific security issues that arise when using PHP and explore techniques for handling them.

16.5.4 PHP Installation Issues

Although PHP is designed to be installed as an Apache module, it can also be installed as a standalone binary in the web server's cgi-bin directory. Although CERT advisory CA 96-11 specifically recommends against installing interpreters in a web server's cgi-bin directory, PHP is designed to try to make such an installation as secure as possible. Nevertheless, we do not recommend this method of installation mostly because PHP runs much faster when it is installed as an Apache module.

If you must install PHP as a separate executable, the PHP manual recommends placing the PHP interpreter outside of the web server's hierarchy. That is, instead of installing the PHP interpreter in cgi-bin, install it as /usr/local/bin/php. To use the PHP interpreter, you need to place #!/usr/local/bin/php at the beginning of each file that uses PHP. Thus, the demo script at the beginning of this section becomes:

#!/usr/local/bin/php <html><head><title>PHP Test</title></head> <body><?php echo "Hello World!<p>"; ?> </body></html>

16.5.5 PHP Variables

One of the features of PHP that makes it very easy to use is the lax way that PHP variables are managed. By default, the following all appear as global variables in the PHP namespace whenever a PHP script is run:

  • Web server environment variables that are typically set for CGI connections, such as HTTP_USER_AGENT and DOCUMENT_ROOT

  • Environment variables that were present when the web server was started up

  • Variables that were provided as part of an HTTP GET

  • Variables that were provided as part of an HTTP POST

  • Variables that were present in a cookie

  • Global variables that are set in subroutine libraries

The danger here is that if a variable is specified in more than one location, one variable will shadow another. What's more, it is not possible for a running PHP script to determine why a global variable was set.

16.5.5.1 Attacks with global variables

For example, you may have a PHP script that depends on an environment variable MAILDIR being set with the location of the mail directory. This environment variable might be set by a library or might be set in the web server's environment space before the web server is started up. Here is such a script:

<html><head><title>PHP Test</title></head> <body> <?php    echo "The value of MAILDIR is $MAILDIR\n";    ?> </body></html>

Under normal circumstances, the value of MAILDIR is /var/spool/mail, and this script displays:

The value of MAILDIR is /var/spool/mail

However, if the script is fetched with a URL such as http://www.simson.net/demo.php?MAILDIR=/etc/passwd, then the script will display:

The value of MAILDIR is /etc/passwd

Many PHP scripts will use the value of global variables to determine their behavior. For example, a script might validate a username and a password, and set an authorized variable if the user is authorized:

<?php if( validate_user($user,$pass)) {   $authorized=1; } ?>

At some point later in the script, your program checks to see if the user is authorized:

<? php if($authorized){   display_secret_data(  ); }

The problem with this approach is that the user can set the $authorized variable in the URL, simply by appending &authorized=1. The script has no way of knowing that the $authorized variable was set by the user and not by the script itself. The solution to this problem is to not rely on the default value of any variable. Instead, manually set each variable before it is used:

<?php $authorized=0; if( validate_user($user,$pass)) {   $authorized=1; } ?>

You can catch many of these errors by calling the function error_reporting(E_ALL) at the beginning of all of your PHP scripts. This function will cause PHP to generate a warning if you use a variable before it is first assigned that is, if you are depending on the default value.

Some programmers recommend checking the PHP arrays HTTP_GET_VARS, HTTP_POST_VARS, HTTP_COOKIE_VARS, and HTTP_POST_FILES to see if a variable was passed in by the user. You can do this, but it is easy to make a mistake, and if the PHP maintainers decide to add a fifth way that the user can specify variables, you'll need to update all of your scripts. It's much simpler and safer to assign the value of "0" or "" to every variable before you use it.

16.5.5.2 register_globals = off

The best solution to the problem of global variables is to prevent environment, GET, POST, Cookie, and Server variables from becoming global variables by setting register_globals = off in the PHP configuration file.

If you turn off register_globals, you will need to manually interrogate the HTTP_ARS, HTTP_POST_VARS, HTTP_COOKIE_VARS, and HTTP_POST_FILES variables, rather than relying on their being globally registered. As a result, this code:

<html><head><title>PHP Test</title></head> <body> <?php print "Hello, $username!<p>"; ?> </body></html>

becomes:

<html><head><title>PHP Test</title></head> <body> <?php     print "Hello, ";     print $HTTP_GET_VARS['username'];     print "!<p>"; ?> </body></html>

Unfortunately, this will also break most PHP programs that you might download from the Internet.

16.5.6 Database Authentication Credentials

Most database systems require that the client provide a username and a password when the connection is made. It is common practice for PHP programmers to embed the usernames and passwords for their database servers directly in their scripts, as shown here:

<?php mysql_pconnect("dbase","user","password"); ...

The problem with this approach is that anybody who can view the raw source of the PHP file can learn the username and password for the database server. If you are on a shared web server, it may be impossible for one group of users to keep another group from viewing the contents of their scripts. In a Unix environment, for example, other users can simply hard link your password-containing scripts to a file in their web server directory with the .txt extension. Even if the other user does not have permission to read your file, the web server will, and thus the user will be able to read the contents of your script and your password.

A better approach to protecting the contents of your scripts is to keep your database passwords in a file and read this out when it is needed. For example:

<?php # # Create the connection # $fp = fopen("/usr/local/adm/dbpasswords/http", "r"); $pass = fgets($fp,14); fclose($fp); mysql_pconnect("mysql.vineyard.net","http",$pass); ?>

The security of this system can be enhanced by using PHP's safe mode and giving each user a different open_basedir. Ultimately, however, the best security comes from giving each user his or her own copy of the Apache web server.

16.5.7 URL fopen( )

A curious feature of PHP is that the fopen( ) function can open URLs in addition to files. The following PHP page will actually display MIT's home page:

<html><head><title>PHP Test</title></head> <body> <?php         $f = fopen("http://www.mit.edu","r");         while($j = fgets($f,65536)){                  print $j;         } ?> </body></html>

When a web browser pulls down this page, it causes the PHP interpreter to open up a connection to www.mit.edu, download the page, and then send the page, one line at a time, back to the web browser.

The problem with PHP's URL fopen( ) feature is that the URL interpretation is done by all PHP functions that open files including the include( ) function. This can be a problem with cascading include files that rely on global variables to specify the directory from which the code is included.

Shaun Clowes' demonstration of this problem involves two files, main.php and loadlanguage.php, which might be used for loading a particular language-specific include file.

In main.php:

 <?php   $libDir = "/libdir";   $langDir = "$libdir/languages";   ...   include("$libdir/loadlanguage.php":  ?>

In libdir/loadlanguage.php:

 <?php   ...   include("$langDir/$userLang");  ?>

The attack is quite straightforward. The attacker simply sends the web server an HTTP GET command that references libdir/loadlanguage.php with the PHP global variable $langDir to be http: and sets the global variable $userLang to be /www.attacker.com/somefile.php3. This causes the web server to download the file http://www.attacker.com/somefile.php and execute the PHP code that it contains. The attack is possible because the file libdir/loadlanguage.php expects that the calling file will set two particular global variables, but it is possible to shortcircuit the calling file and call the library file directly.

Granted, these sorts of attacks are hard to carry out: if you write all of your own scripts and keep them secret, even if you have these vulnerabilities, they probably won't be used against you. But it can be difficult for a site to keep its scripts secret, and many sites make use of scripts downloaded from public sources.

16.5.8 Hide Your Scripts

Because many problems may be lurking in your PHP scripts, we recommend that you not make your scripts publicly available. This can be harder than you imagine. For example, you need to be sure that your PHP scripts are always processed by the PHP interpreter. For example, they should not be accessible by FTP.

The PHP documentation recommends that you make it impossible for an attacker to turn on debugging code that you may have placed in your own scripts. For example, many programmers typically use variables such as debug or showerrors to put their scripts into debugging mode. But an attacker can do the same thing using PHP's powerful global variable facility. For example, this code snippet, placed anywhere on the Internet, could be used to probe the URL http://www.ex.com/index.php for debugging code:

<form method="post" action="http://www.ex.com/index.php?errors=Y&showerrors=1"&debug=1"> <input type="hidden" name="errors" value="Y"> <input type="hidden" name="showerrors" value="1"> <input type="hidden" name="debug" value="1"> <input type="submit" name="probe"> </form>

Finally, you can hide the fact that you are using PHP entirely, by configuring your web server so that an extension other than .php is used, as follows:

# Make PHP code look like unknown type AddType application/x-httpd-php .bop .foo .133t

Alternatively, configure your web server so that the PHP parser is used to parse all HTML files, rather than simply those ending with .php. This is shown here:

# Make all PHP code look like html  AddType application/x-httpd-php .htm .html

16.5.9 PHP Safe Mode

PHP safe mode can be used to disable certain functions in the PHP interpreter based on where the particular PHP script resides. Safe mode is particularly useful for ISPs, where different individuals or organizations are using a shared resource.

The PHP manual states: "It is architecturally incorrect to try to solve this problem at the PHP level, but since the alternatives at the web server and OS levels aren't very realistic, many people, especially ISPs, use safe mode for now."

In fact, some ISPs do set up their web servers with a separate Apache process for each customer. Unfortunately, this can be exceedingly resource-intensive and is not necessary for many applications. Thus, safe mode is widely used.

16.5.9.1 Controlling safe mode

The configuration flags that control safe mode are shown in Table 16-1.

Table 16-1. PHP configuration flags that control safe mode

Configuration value

Default

Effect

safe_mode

Off

Turns safe mode on or off.

open_basedir

If this value is set, then all file operations (e.g., fopen, fread, fclose, etc.), must take place underneath this directory. Setting open_basedir can be used as an alternative to safe mode or in conjunction with it.

safe_mode_exec_dir

PHP will only run executables that are contained within thisdirectory.

safe_mode_allowed_env_vars

PHP_

Users can only modify environment variables that begin with PHP_.

safe_mode_protected_env_vars

LD_LIBRARY_PATH

Users cannot modify these variables at all.

disable_functions

Allows individual functions to be disabled.

16.5.9.2 Safe mode restrictions

When safe mode is on, the following restrictions are in place:

  • Most commands that result in files being opened, renamed, linked, or otherwise modified (e.g., fopen( ), dmbopen( ), dbase_open( ), etc.) will only allow files to be opened that have the same UID as the owner of the script that is being executed.

  • The system( ) function can only execute scripts that are in the safe_mode_exec_dir.

  • The dl( ), backtick (e.g., `command`), and shell_exec( ) functions are disabled.

For more information about safe mode, see http://www.php.net/manual/en/features.safe-mode.php.

PHP Configuration File Settings

In his paper "A Study In Scarlet: Exploiting Common Vulnerabilities in PHP Applications," Shaun Clowes recommends this checklist for securing PHP environments:

set register_globals=off

This will prevent users from setting variables in your PHP scripts.

set safe_mode=on

This will enable safe mode, which significantly improves the security of PHP scripts. "This is a great option for ISP environments (for which it is designed), but it can also greatly improve the security of normal PHP environments given proper configuration," Clowes writes. "It can also be a complete pain in the neck."

set open_basedir

This restricts the PHP system to a particular directory hierarchy that you specify.

set display_errors=off, log_errors=on

This causes PHP to write its errors to a log file, rather than displaying them in the web browser. This makes debugging scripts harder, but it also makes it more difficult for an attacker to reverse-engineer your scripts. A good compromise is to set display_errors=on for development systems but set it off for production environments.

set allow_url_fopen=off

This will prevent PHP from opening URLs when you think it is opening files.

only for RuBoard - do not distribute or recompile


Web Security, Privacy & Commerce
Web Security, Privacy and Commerce, 2nd Edition
ISBN: 0596000456
EAN: 2147483647
Year: 2000
Pages: 194

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net