Securing Your PHP Application from Hackers
by Kevin K. Nelson
I've always found programming to be very easy. In an "introduction to programming" class that I took many years ago, I was given a "group project" with two other students to develop a "simple application" in JSP. I wasn't satisfied with simple, I wanted "real life", so I left my fellow group members standing lost and confused as I wrote a complete "Real Estate Office Management" application. While that is fairly impressive considering my lack of experience with programming, the application that I wrote was anything but secure, and I am thankful that I never tried to sell it to anyone. It is now years later, and I'm STILL learning about web application security and continuing to find new and better ways to implement that security within my applications...and I'm certain that I have mountains more to learn.
A large portion of security issues are handled by the software creators themselves (e.g. php's creators), and another large portion are, or should be, handled by professional system administrators. However, that still leaves a small portion of security issues that need to be handled by the programmer. For the scope of this article, I will focus on security issues within PHP, but many of these principles can be carried into other scripting languages (except for the PHP Settings section).
PHP Settings for "best practices"
- register_globals should be OFF
- allow_url_fopen should be OFF
- magic_gpc_quotes should be OFF (or worked around)
- safe mode should be ON
First, "register_globals" should ALWAYS be turned off. Having register_globals turned on opens up the possibility for a hacker to set the value of a variable that is not properly set within the application. When getting posted data, etc., the auto-global $_POST should be used. Second, if possible you should turn magic_gpc_quotes off, because it is a very bad practice to rely on magic quotes to escape variable strings for you. For a long time, the server that my company used had magic quotes turned on, and I couldn't turn it off or I'd risk other applications breaking. So, I settled with allowing magic_quotes to do the escaping for me and inserted things into the DB as-is. Unfortunately, this kind of method is not transportable...if I try to move that code to another server without magic_quotes on, the code will break and open up many security holes. So, it is best that--if magic_quotes is on--you loop through $_POST and $_GET and stripslashes() from each of the array values and then reassign it. Then, simply make sure that you properly validate all variables and use mysql_escape_string() etc., within SQL queries, which gets us to our next section:
One of the most prevalent ways that applications are compromised is when the programmer does not properly validate the user input. When a hacker submits invalid data to an application they may be able to get errors that will give them more information on the internal structure of the application, and possibly find a way to insert a "SQL Injection." SQL Injections are when data is posted to the application that doesn't get validated properly before being put into a SQL query and then allows the hacker to insert their own SQL commands and gain control over the database. In my experience with many open source applications, this is the most common way for them to be compromised. The best way to avoid this is to make sure that you validate ALL input that you allow to come from a user. So, to give you an idea of some of the steps you should take to validate input, here's a simple example in PHP:
// FOR DATABASE
// mailing_list (
// name VARCHAR(32) NOT NULL,
// email VARCHAR(64) NOT NULL,
// can_email BOOL NOT NULL
// ASSUMING $_POST VARIABLES ARE SET
$strName = substr($_POST['name'],0,32);
$strEmail = substr($_POST['email'],0,64);
$iCanEmail = (int) $_POST['can_email'];
$strSQL = "INSERT INTO mailing_list
(name, email, can_email)
In the above example, before allowing the name, e-mail, and can_email variables to be inserted into the database, I do the following:
- Clip the string to the maximum length allowed by the database column so that MySQL doesn't have to deal with it.
- strip_tags() to strip HTML/PHP tags out of the string since names and e-mails don't need HTML. The primary reason
for hackers to do is input an image like so to obtain cookie info (session ids): <script>document.write("<img
- I cast can_email as an integer. If someone tries to insert a string, it will become a zero.
- Before putting any data into a SQL query, I run mysql_escape_string() on the variable to make sure that all quotation marks,
etc., are escaped so that a SQL injection can't occur. Honestly, it is pointless to do this on the $iCanEmail variable since I
casted it as an integer, but in the event that I forget to cast the variable, this will help to ensure that a SQL injection
still doesn't occur.
- In a real-life application, I would probably also validate that the everything was actually filled out and that the
e-mail was properly formatted before submitting it to the DB since I don't need to add invalid data to a mailing list, but
I figured I'd skip the regular expression tutorial for the moment :)
Other Security Measures
As time allows, I will try to add moe tips on how to protect your website applications. If you have any tips yourself, feel
free to e-mail them to me.