Thursday, August 11. 2005
During the last months, more and more self proclaimed PHP security experts have started spreading the FUD, that register_globals is evil and that you should always switch it off, when you develop or deploy an application. This has resulted in vendors ignoring or playing down vulnerabilities, which are only exploitable when register_globals is turned on. Even when their own hoster has this option activated, they claim the vulnerability is in PHP's register_globals and not in their application.
I strongly disagree with this kind of argumentation and because I see similiarities with the actions of a certain big software company I usually refer to it as Trustworthy PHPing.
register_globals is not a security vulnerability on it's own. It is however an operation modus, that allows to exploit codepaths that are using not properly initialised variables. Problems with uninitialised variables are older than PHP itself and other languages like C share them. One example for this is the code execution vulnerability in PHP's 4.2.0-4.2.1 fileupload code that I have disclosed in the middle of 2002.
With this in mind, it is of course better for a server owner to switch off register_globals, because it stops exploits against installed web applications. The problem with this is, that hosters have a lot of customers, that use older PHP applications, that only work with register_globals being turned on. If you look at examples like Geeklog you will realise, that these applications are not automatically insecure.
So the message is: switching register_globals to off is a good advise for a "Howto set up a secure PHP server". But under no circumstances should this option be mentioned in a tutorial about writting secure PHP code, because this educates people in the wrong way. They start to believe, that register_globals is turned off everywhere and don't stop to write insecure web applications. My experience with some PHP application vendors in the last months have shown, that this downfall has already started.
It is important to teach people to use E_NOTICE to find uninitialised variables1 and it is important to teach them, that the PHP world is a very heterogeneous one. It is not enough to write secure code for your very own server. If a PHP application wants to survive in the wild, it must atleast deal correctly with the different combinations of magic_quotes_gpc and register_globals, otherwise it should be completely avoided.
Coming back to register_globals: a secure PHP application should always
- be developed with E_NOTICE to catch uninitialised variables1 (best practice)
- deregister global variables if register_globals is activated (additional best practice)
- ship a .htaccess file that disables register_globals (to speed up step 2)
- tell people to disable register_globals on their servers (to speed up step 2)
1) It is important to realise that E_NOTICE is not enough to catch not properly initialised variables. It will only find unitialised variables.
<?php
$allowed_tag[1]='b';
$allowed_tag[2]='i';
$allowed_tag[3]='pre';
...
if (in_array($tag, $allowed_tag)) { ... print out the tag ...
}
?>
It should be obvious, that it is possible to inject f.e. allowed_tag[4]=script without triggering any E_NOTICE. And if it were forbidden_tag it would be possible to set forbidden_tag to a simple string, so that registering the array elements from within the script fails.
<?php
// pseudo injected through globals
$forbidden_tag='failing after here';
...
// fails because it is handled as stringoffset
$forbidden_tag[1]='script';
...
if (!in_array($tag, $forbidden_tag)) { ... in_array will fail with a warning that ...
... forbidden_tag is not an array when attacked ...
}
?>