Cross-site request forgery (CSRF or XSRF)
CSRF occurs when an attacker tricks users into performing actions within their security
context. If no security measures are in place, hackers can do this regardless of
whether the form method is
POST. Between the two, CSRF attacks that use the
GET method are the biggest threat because the request can be forged
using only a URL, which an attacker can use as the source of an image. If the attack
has the ability to arbitrarily set the source of an image within the system, hackers can leverage it to launch an on-site request forgery (OSRF) attack.
Almost every action in CMA can be recreated as a CSRF attack. Listing 10 is an example of a
GET-based attack that changes the targeted user's password to new_password.
Listing 10. Password changing CSRF example
<html> <body> <img src="http://localhost/CMA/insecure/preferences.php?firstname=John&lastname =Doe&newpassword1=new_password&newpassword2=new_password&userid =2&imagecompression=5" /> </body> </html>
If the GET method does not work, the attacker can attempt to forge the request using
POST (see Listing 11).
Listing 11. Password changing CSRF example using the
<html> <body onload="document.forms.submit()"> <form method="POST" action="http://localhost/CMA/insecure/preferences.php"> <input type="hidden" name="firstname" value="John" /> <input type="hidden" name="lastname" value="Doe" /> <input type="hidden" name="newpassword1" value="new_password" /> <input type="hidden" name="newpassword2" value="new_password" /> <input type="hidden" name="userid" value="2" /> <input type="hidden" name="imagecompression" value="5" /> </form> </body> </html>
The outcome of viewing the rendered HTML in Listing 11 is the creation of a request that is identical to that of a legitimate user updating user preferences, but all form values are controlled by the attacker.
You can prevent CSRF in a couple of common ways. The easiest way to implement is to check the referrer in the HTTP request (see Listing 12); if the request is not from a trusted source, it should be rejected. The more granular the referrer checking, the better the security.
Listing 12. A basic referrer check implementation
if (strpos($_SERVER["HTTP_REFERER"], $app_host . $app_path) != 0 && strpos($_SERVER["HTTP_REFERER"], $app_path) != 0) die("Invalid request");
This approach, though, is not foolproof. A more secure countermeasure is the employment of a security token. With each protected form, the server includes a long, sufficiently random token value. Each token value is tracked server-side to ensure that it is used only once and expires after a predetermined amount of time. On form submission, if the value is absent, invalid, or expired, the request is rejected on the grounds that it is most likely forged. Without the ability to guess the token value, an attacker is not able to craft an attack. If this security mechanism is applied to every page in the application, it also serves to prevent reflected XSS.
In the upcoming sections, you'll look at several types of server-side vulnerabilities.