Although PHP 5.3 is still in alpha stage and certain features like the PHAR extension or the whole namespace support are still topics of endless discussions it already contains smaller changes that could improve the security of PHP applications a lot.
One of these small changes is the introduction of a new php ini directive called request_order. request_order is the response of the PHP developers to me preaching for years that using $_REQUEST is not only deprecated but actually dangerous for PHP applications. With request_order it is now possible to control in what order $_REQUEST is created and what variable sources are taken into account. This finally allows removing cookie data from $_REQUEST without removing them from $_COOKIE also.
Because removing cookies from $_REQUEST might break badly written software request_order is not set by default. However the recommended setting by the PHP developer is to set it to “GP” which means only $_GET and _POST data is merged into $_REQUEST with $_POST data overwriting $_GET data.
To learn why using $_REQUEST is a bad idea and what Delayed Cross Site Request Forgeries/Hijacking are continue reading…
$_REQUEST and Cookies
PHP application developers often use $_REQUEST instead of $_GET or $_POST because they do not care about the source of input. This has been considered bad practice for a while, because it is actually a violation of the idea behind GET and POST requests: GET is meant to retrieve data, POST is meant to manipulate data. And others have wrongly claimed that using POST instead of GET is a protection against CSRF. Nevertheless PHP application developers still use $_REQUEST a lot, because they cannot see the security threat in using it.
What most of them forget is that $_REQUEST does also contain $_COOKIE data and cookies unlike $_GET and $_POST data are shared among a (sub-)domain. So an application must actually expect that there might be cookies alien to the application. These cookies could be an attack on the application but aren’t necessary. However their presence in $_REQUEST results in application input filters going crazy or they might influence the application logic.
Therefore it is important to remember that cookies might be legal cookies of another application on the same host. And it is also important to remember that some browsers like Firefox 2 does allow an application to set cookies valid for a whole country if the domain is like *.co.uk or *.co.kr. While this allows cross domain user tracking, it also means any application in the country could set a cookie that is seen by your application and considered an attack.
Cookie Denial of Service (DOS)
Taking this into account it should be obvious that any application blocking requests because of some value appearing in $_COOKIE or $_REQUEST is vulnerable to denial of service. Once an attacker is able to get a cookie into the browser of a user, which is possible through XSS in one application on the same domain or cross domain vulnerabilities in browsers, it will trigger the request blocking in the application with every request. The user will not be able to use the application anymore unless the cookie expires or he manually deletes it. However the average user does not have a clue how to delete a cookie, which means he will be denied access forever.
NOTE: Due to PHP’s way of ignoring trailing spaces in variable names and because cookies might be set (sub-)domain wide or path wide, it is not possible for the application to kill the cookie by issuing a simple Set-Cookie HTTP header.
Many open source PHP applications are vulnerable to Cookie Denial of Service because they introduced code similar to the following example to protect against PHP’s GLOBALS overwrite problem.
if (isset($_REQUEST['GLOBALS'])) { die("GLOBALS Overwrite attack attempt!!!"); }
Because of this it is possible to deny a user access to a lot of sites in Korea or the UK by just creating a GLOBALS=1 cookie for *.co.kr/*.co.uk in older Firefox versions. Another attack that hits many PHP applications is creating a cookie called action=logout.
Delayed Cross Site Request Forgeries/Hijacking
When $_REQUEST is used by an application to react on user input instead of just $_GET or $_POST an attacker can inject certain values or actions into an application through injected cookie data instead of just killing it with a Cookie DOS. This attack is similar to a Cross Site Request Forgery with the difference that it actually hijacks a user request instead of simply forging it and that it happens with a delay: After the cookie is injected the CSRF is executed the next time the user uses the site.
Because the actual attack relies on hijacking an actual user request that is abused by manipulating by adding or modifying some input variables people might prefer to call it Cross Site Request Hijacking. It is important to realise that a delayed hijacking is different from just forging the request. This also means that traditional CSRF protections like form tokens or asking the user for his password are ineffective against this kind of attack. Because the attack just changes some of the variables within a request the secret form tokens and/or user submitted passwords of the original request will be transmitted correctly.
A vulnerability like this was found and disclosed in phpMyAdmin a while ago. Within phpMyAdmin it was possible to inject a cookie that would execute arbitrary SQL statements on the server the next the user logged into his phpMyAdmin account.
Another incarnation of this vulnerability class was found within a form software where the admin configuration was handled by code similar to this.
// save only modified admin options // BEWARE THIS CODE IS VULNERABLE foreach ($_REQUEST[‘options‘] as $key => $val) { if (isset($options[$key]) && $options[$key] != $val) { saveOption($key, $val); } }
In this example an attacker that is able to inject a cookie titled options[includePath] into the admin’s browser will be able to remotely include arbitrary PHP code. Because the attack relies on Delayed Cross Site Request Forgery/Hijacking the attack is even possible when the admin is not currently logged into the administrative interface. The payload sleeps and will become effective once the admin tries to change the forum configuration the next time, although there is a CSRF protection in place.
Conclusion
Once PHP 5.3 is out it is recommended for hosters to set request_order to “GP” on all the servers running arbitrary PHP applications to protect applications from this kind of Cookie DOS or Delayed Cross Site Request Forgery/Hijacking vulnerabilities.
PHP Application developers on the other hand should finally move away from using $_REQUEST for user input, because it is cleaner and more secure.