Cross Site Request Forgery

30 November -0001
Justin C. Klein Keane
April 6, 2007

What it is

A cross site request forgery leverages the fact that many popular web sites use session authentication, but don't follow up by verifying the session. The problem is that sessions are handled by cookies, and relying on the cookie alone isn't enough to validate the source of data. A cross site request forgery uses a cookie that has been generated by a session to validate a request (usually a form post) from a third party web site.

By way of example imagine that we have the website securesite.tld that requires users to log in. Once logged into securesite.tld users can manage their account, and even change their password by using form posts. For the purposes of this example we'll assume that a user logs into securesite.tld, browses around for a little bit, then browses off to other websites. One of the other websites the user browses to contains a hidden form that contains the same fields as a form on securesite.tld, but with values assigned by the attacker. The user's browser unwittingly, and invisibly, submits this form back to securesite.tld. Securesite.tld recognizes (via cookies) that the user is valid and has already authenticated so it processes the form just as if the user had submitted it deliberately. Thus the securesite.tld server carries out instructions on the users behalf without the user ever being aware of the request or consenting to the instructions.

Description of Attack Vector

The cross site request forgery requires that the attacker have knowledge of the form composition and targeting beforehand. This is not as far fetched as it seems given the high volume of users on some sites. If the attacker is also a valid account holder on the target website they might have legitimate access to these resources. Following our above example we'll assume the attacker is also a valid user on securesite.tld and knows what the forms on that site look like. Let's assume the form used to change your password has two fields, one called new_pass, and one called new_pass_confirm. These fields appear in the form named theForm and they submit to the page securesite.tld/changepass.cgi. The attacker creates their own web page at attacker.tld/fake.htm. Then they embed a form in the page, using hidden form fields so that the user can't see the form. They fill in the values they want and perhaps even have the form submit through a hidden iframe so the user will never be aware the form existed. Such a form might appear like:

<form name="evil_form" action="securesite.tld/changepass.cgi" 
	method="post" target="i_frame">
<input type="hidden" name="new_pass" value="evil_new_pass"/>
<input type="hidden" name="new_pass_confirm" value="evil_new_pass"/>
</form>
<iframe name="i_frame" width="0" height="0"></iframe>
<script>
document.evil_form.submit();
</script>

Now all the attacker has to do is trick a victim into visiting the site (for instance by posting to a forum on securesite.tld). Once the victim visits the attackers page their password is changed without the victim ever being aware.

Description of Vulnerability

The way this works is that most applications use cookies for session authorization. Once you successfully authenticate you get a cookie that can be used to verify that you've already authenticated to the application. This cookie is specific to the URL that originated the cookie, so it can't be used outside the site that generated it. This cookie is passed along behind the scenes in any request that the browser makes to the corresponding site. In our attack example above the form submission carries with it the authenticated cookie that the site uses to verify that the user is already logged in.

This cookie persists at least until you close the browser, regardless of your browser settings. Even if the 'logout' script destroys the cookie the application could still be vulnerable. The reason for this is that users often ignore log out functionality and simply browse away from sites. This leaves the cookie in the browser even if the cookie is set to expire (cookies are cleared from cache when the browser closes and not before).

Using a cookie is a good way to validate a users since the cookie can carry a token that can be validated by the site but can't easily be guessed or spoofed by an attacker. A sufficiently complex token can be infeasible to guess or recreate. Also, if the application keeps track of when it issues cookie tokens it can expire them after a reasonable time. This can help to narrow, but does not eliminate the threat window. The essential problem is that the target site has no way to identify the origin of data being submitted. The data is being provided by a malicious server, but it is being composed and executed by the victim's browser, with all the rights and privileges of the victim.

Remedies

Fortunately there is a solution to this problem. The solution is to simply only allow forms to post if they are generated from the trusted server. This then creates the problem that the server must be able to distinguish which form posts were generated by the server. To accomplish this the server must generate HTML forms with a message embedded in the form to be read back by the server on submission. The easiest way to do this is to generate a random token that cannot be guessed by an attacker, and that has a limited life span, and include this token in a hidden field in the form. This token has to be pseudo-random (passes the 'security' check for randomness) and regenerated each session. This token can be stored in a database to be used by the application (for easy access and checking). The application times out tokens on a schedule similar to that of session time out. Each time a form process occurs the token is submitted in a hidden field. The application not only checks the session for viability (via the cookie) it also looks up the token to make sure it is valid and matches the session (each user gets their own tokens). This process can be expanded to include tokens in GET requests (for instance links in applications that might download resources). In this way the server can verify that not only is the user in possession of a valid session, but also that the form submitted was generated by the server.

Using this second factor an attacker would have to include the hidden token field in their malicious form, but if the token is random it will be impossible for them to guess what the token could be. Without the token the form post (or request) will fail and resources will remain secured. Only legitimate requests posted from pages the server generated will be honored.