PHP Security - Specifics

Register Globals

One of the biggest security mistakes built into PHP itself is "register globals". By exposing all of the fields in your script in the global namespace you provide those trying to compromise your script with access to any security hole that you may have inadvertently created in your script.

The biggest problem with using register globals is that you have no way to tell within your script which fields have been properly filtered and which may be tainted. This is because turning register globals on effectively taints all of the fields in your script right from the start and the only way you have to untaint fields is to filter them. Unfortunately there is no way you can load the filtered data into separate fields where you know that the field isn't tainted through the way you have named it when register globals is on as in that situation there may be a way for someone to inject bad data into any field in your script.

With register globals off (as has been the default since version 4.2) only the fields that PHP loads the POST, GET, and Cookie data into in the first place start out tainted and need filtering (although any fields you read from elsewhere should be sanitised to ensure they haven't been compromised). None of the fields that you actually create within your script can be tainted unless you copy a tainted field into it without filtering it first.

All that having register globals turned off means is that you need to read in the data passed from a form using the $_POST[] array, variables passed in the querystring from the $_GET[] array, and coolies from the $_COOKIE[] array instead of just being able to reference them directly using PHP variables with the same names.

Instead of being able to reference an email address passed from a form into the script using $email you need to reference it using $_POST['email'] instead. This allows us to filter the field in order to ensure that it actually does contain an email address using:

$email = filter_var($_POST['email'], FILTER_VALIDATE_EMAIL);

We can then test the value of $email and if it is false then we know that the value that was input into that field does not validate as being in the correct format to be an email address.

Using this statement means that $email and $_POST['email'] do not necessarily reference the same data as they would if register globals was turned on. We know that $email either contains something that could be an email address or false whereas $_POST['email'] can contain anything at all depending on what was typed in. Since the field is supposed to contain an email address there should not be any way in which something that looks like an email address can compromise the security of our script. Ssince we haven't actually checked if the email address really exists or is just a value that could be created as an email address we can't say for certain whethert actually is an email address, just that it can be.

Of course while I have used email address in this example the same applies to all of the fields that are input into your script. With register globals on you have no way to tell if you have remembered to actually filter ALL the possible fields that can be used to pass data into your script (since any field can be used to do that if you don't code to prevent it). With register globals off you know that the only way that a regular variable in your script can contain a value is if you assigned something to it earlier in the script. Accidentally leaving out an assignment statement to filter an input field will therefore break your script rather than just opening up a security hole for later exploitation.


This article written by Stephen Chapman, Felgall Pty Ltd.

go to top

FaceBook Follow
Twitter Follow