ONLamp.com    
 Published on ONLamp.com (http://www.onlamp.com/)
 See this if you're having trouble printing code examples


PHP Foundations PHP Security, Part 1

by John Coggeshall
07/31/2003

In my last two columns (Common Style Mistakes, part one and Common Style Mistakes, part two), I discussed some common bad practices to avoid when writing PHP scripts which can make them more difficult to read and more prone to bugs. In today's column I'll change gears and discuss the meat of this series: the importance of security when working with PHP.

The Importance of Thinking About Security

More than meets the eye

The most effective and often overlooked measure to prevent malicious users from compromising your scripts is to consider the possibility it could happen when you write them. It's s important to be mindful of the possible security implications of your code.

Consider the following example function designed to simplify the life of a developer who writes a great many text files from PHP scripts:

<?php
function write_text($filename, $text="") {
	static $open_files = array();

	// If filename is null, close all open files
	if ($filename == NULL) {
		foreach($open_files as $fr) {
			fclose($fr);
		}
		return true;
	}
	$index = md5($filename);    
       
	if(!isset($open_files[$index])) {
		$open_files[$index] = fopen($filename, "a+");
		if(!$open_files[$index]) return false;
	}
	fputs($open_files[$index], $text);
	return true;
}?>

This function takes two parameters by default, the filename and the text to write to that file. The function will first check to see if it has already opened that file in the past; if it has, it will reuse the old file reference. Otherwise, it will create one if one doesn't exist. In either case, the text is then written to the file. If the filename passed to the function is NULL, then all the opened file references are closed. An example usage is provided below.

If the developer is writing a number of text files in this manner, this function will make his code look much cleaner and easier to understand. Let's assume that this function lives in a separate file which is included in the scripts which require the function. Here's one of the scripts where it's used, called quotes.php:

<html><body>
<form action="<?=$_SERVER['PHP_SELF']?>" method="get">
Choose the nature of the quote:
<select name="quote" size="3">
<option value="funny">Humorous quotes</option>
<option value="political">Political quotes</option>
<option value="love">Romantic Quotes</option>
</select><br />
The quote: <input type="text" name="quote_text" size="30" />
<input type="submit" value="Save Quote" />
</form>
</body></html>

<?php
    include_once('write_text.php');

    $filename  = "/home/web/quotes/{$_GET['quote']}";
    $quote_msg = $_GET['quote_text'];

    if (write_text($filename, $quote_msg)) {
       echo "<center><hr><h2>Quote saved!</h2></center>";
    } else {
       echo "<center><hr><h2>Error writing quote</h2></center>";
    }
    write_text(NULL);
?>

As you can see, this developer has used the write_text() function created previously to develop a system to allow users to submit their favorite quotes, which are then saved to a text file. Unfortunately, though the developer may not know it, this script could also allow a malicious user to compromise the security of the web server.

Perhaps right now you are scratching your head and wondering exactly how such an innocent looking script poses such a security risk. Instead of asking you to figure it out yourself, consider the following URL, remembering that the script itself is called quotes.php:

http://www.somewhere.com/fun/quotes.php?quote=different_file.dat&quote_text=garbage+data

What will happen when this URL is presented to the web server? Obviously the quotes.php script will be executed; but instead of writing a quote to one of the three desired files, a completely new file called different_file.dat will be written with a string garbage data inside of it. Obviously, this is not desired behavior at all. In fact, a malicious user might even be able to create an account by accessing the Unix password file by specifying ../../../etc/passwd for the quote parameter (although that would require the web server to be running scripts as a superuser, and if that is the case you should stop reading this and fix that right now). Perhaps the most serious implication of this script is it could even be used to allow someone to write and execute arbitrary PHP scripts, if the /home/web/quotes/ directory were accessible from a browser. The evil possibilities are endless.

There are several solutions. If you only need to write a few files in the directory, consider using an associative array to store the file names. If the user input exists in the associative array, it's safe to write. Another option is to strip out all non-alpha and non-numeric characters, to make sure there are no directory separators. Yet another idea is to check the file extension to make sure it won't be executed by the web server.

Related Reading

Programming PHP
By Rasmus Lerdorf, Kevin Tatroe

The bottom line is simple. As a developer you must be aware of more than what your scripts do under the desired circumstances. What will happen if invalid data is entered into a form element? Is there any way a malicious user could make your script behave in an unintended way? What measures are being taken to prevent these attacks? Your web server and PHP scripts are only as safe as the weakest security link, so it's important to identify these possible weak links before they're identified for you.

Common security-related mistakes

To give you a few pointers, here's a brief and incomplete list of coding or administrative failures which can compromise security:

More on security soon

I cannot stress enough the importance of thinking about security in order to protect your servers from malicious users. Now you should be looking at your scripts in a whole new light. With a little experience, soon you'll be catching these potential security lapses before you even write the code to create them. The next column will discuss a few more common ways security is compromised in PHP scripts and the steps you as a developer can do to minimize them.

John Coggeshall is a a PHP consultant and author who started losing sleep over PHP around five years ago.


Read more PHP Foundations columns.

Return to the PHP DevCenter.


Copyright © 2009 O'Reilly Media, Inc.