Today on Hacks From Pax we'll be discussing PHP web application security. PHP is a great language for rapidly developing web applications, and is very friendly to beginning programmers, but some of its design can make it difficult to write web apps that are properly secure. We'll discuss some of the main security "gotchas" when developing PHP web applications, from proper user input sanitization to avoiding SQL injection vulnerabilities.

Many PHP application vulnerabilities are caused by not properly initializing variables. This is an example of how PHP, by not requiring the developer to initialize a variable before using it, sacrifices security for ease of use. For example, the following code is easily exploitable.
if (user_auth()) {
  $access = true;
}
if ($access) {
  do_sensitive_things();
}
This could be exploited by tacking an ?access=true to the end of the url, and the if ($access) test would be passed despite the user_auth() function returning false. This hole could be closed easily by adding a $access = false; at the top of the script, but not all security holes are this easy to spot.

Thankfully, PHP now defaults the register_globals option to off. This setting would pass the access variable sent by the url to the script as $_GET[access] rather than just $access. This closes off many of these types of vulnerabilities, but when writing PHP code, especially code for distribution, you should never assume that this option will be set correctly, and always initialize your PHP variables. Users in a shared hosting environment may not have the ability to set these options to their most secure setting.

  • Always initialize PHP variables before using them.
  • Always set register_globals to off, but never write code that assumes this setting.
  • You can use the ini_get() function to determine if register_globals is set at runtime.

Another common cause of PHP application holes is improper sanitization of user provided data. For example, if you allow a user to fill out a form and then pass data from a field on that form to a function like system() or exec() the data could contain something malicious, like an ; rm -rf * command tacked onto it.

  • Never trust user provided data.
  • Beware functions that launch system commands, think long and hard about checking any data that is passed to them.

Another related but common security flaw in PHP applications is a SQL injection vulnerability. The magic_quotes_gpc option can mitigate this, but as with register_globals you should not assume this setting is on.

For example, in your PHP script you might ask the user for a user id and password, and then check for the user by passing the database a query.

SELECT * FROM users WHERE name='$username' AND pass='$password';
However, if the user logging in is malicious and devious, he may enter the following as his password:
' OR '1'='1
This causes your query to become:
SELECT * FROM users WHERE name='known_user' AND pass='' OR '1'='1';
The user has just logged in with no password, and your application has been penetrated. To avoid this, check for the status of magic_quotes_gpc() using the ini_get() function and if it is disabled, pass all user input that must be included in a query through addslashes(). This will escape the single or double quotes in the user input with backslashes, thereby thwarting the attempted SQL injection attack.

  • Use magic_quotes_gpc, but don't assume it is on or depend on it.
  • The addslashes() function should be used on user data passed to SQL queries.
  • Again, you simply cannot trust user provided data.

The PHP online manual contains an entire chapter on PHP security. It's an excellent resource, and goes into much more detail on the PHP security issues I've discussed in this article. Until next time, stay secure, and don't blindly trust any user provided data.
--
Pax Dickinson has over ten years of experience in systems administration and software development on a wide variety of hardware and software platforms. He is currently employed by Guardian Digital as a systems programmer where he develops and implements security solutions using EnGarde Secure Linux. His experience includes UNIX and Windows systems engineering and support at Prudential Insurance, Guardian Life Insurance, Philips Electronics and a wide variety of small business consulting roles.