Security of PHP scripts

Security of applications is one of the most important aspects of programming today - and one of the most overlooked and misunderstood. Now we will look at different security problems that face PHP developers and techniques to solve them.

Python vs. PHP: Choosing your next project's language

User supplied data

PHP is designed with user input in mind. This is why it is so easy to get access to user supplied data in PHP, but it also leads to some of the biggest security problems with PHP.

Consider the following example, where the variables $username and $password are supplied from a login form:

$ret = auth($username,$password);

if($ret) { $loggedin = 1; }

if($loggedin) { secure_data(); }

The first line of the script authenticates the username and password supplied with a user defined function auth(). This hypothetical function returns true if the user was authenticated. Next, the script sets the variable $loggedin to signify that authentication was successful. Later in the script, the variable $loggedin is tested; if it is true, the hypothetical function secure_data(), which outputs data that only authenticated users should see, is called.

The problem with the script is that the variable $loggedin could easily be supplied by the user. This means that even if auth() returns false, the script will expose the restricted data. The easiest way to fix this is as follows.

$ret = 0;
$loggedin = 0;
$ret = auth($username,$password);

if($ret) { $loggedin=1; }

This time, the variables in the script are initialised to false, overriding any value the user of the script might have supplied.

There is an even more thorough way of doing this: disallowing registration of user variables from outside the script. This involves two steps. First, you will need to set Â'register_globals = off' in the PHP configuration file, php.ini. Second, you will need to alter the way you access GET, POST and cookie variables.

With register_globals set to off, all user supplied variables must be accessed via the associative arrays $HTTP_GET_VARS, $HTTP_POST_VARS or $HTTP_COOKIE_VARS. For example, if the form that supplied the authentication data to the script above used the POST method, the variables would be obtained in the following way:

$ret = auth($HTTP_POST_VARS["username",$HTTP_POST_VARS["password"]);

Even if malicious variables were passed to the script, they would not be accessible.

Validation of data

Many programmers assume that users will use applications the way they're intended. Many hackers and crackers, however, use applications in very unexpected ways, often exposing bugs. For example, consider a script which retrieves data from a PostgreSQL database based on an integer, $n, supplied from the user.

$res = pg_exec($conn,"select * from data where id=$n;");

This is fine if $n is one of the numbers expected. There are two potential security problems, however.

Consider a situation where the rows in the table relate to particular users and $n is a unique user identifier. If it is not unique, a malicious user could pass the script an identifier other than his or her own and gain access to someone else's account. So, PHP scripts should always verify that data they are receiving from a user is the data they expect to receive from that user.

The second way the script could open a security hole is by assuming that $n is an integer. Imagine if a user passed the following string instead: '1; DELETE FROM data;'. This would result in the following query:

$res = pg_exec($conn,"select * from data where id=1; DELETE FROM data;");

This is called an SQL injection attack. Instead of supplying an integer, the user has supplied an integer, a command terminator (;) and another SQL command - which deletes all rows from the table! The pg_exec() function sends both queries to the database server and each is executed.

There are three ways to combat such an attack. First, the script should not connect to the database as the PostgreSQL super user. Rather, it should use an account which can only retrieve data, not delete it (for more information on creating database users, see the PostgreSQL documentation).

On top of this, the script should be rewritten as follows:

if(is_numeric($n)) {
$res = pg_exec($conn,"select * from data where id='$n'");
/* ... */

The script both checks that the variable is an integer and encapsulates it inside quotes in the query string.

People looking to practise secure programming technique should look at the scripts covered in previous columns and develop validation routines for the data provided.

Join the newsletter!

Error: Please check your email address.

More about ApacheARSCA TechnologiesHewlett-Packard AustraliaHP

Show Comments

Market Place