Friday, February 6, 2009

double-submit cookie CSRF defense and HTTPOnly

Let's start with reviewing the Wikipedia paragraph on this subject.

A variation on this approach is to "double submit" cookies. If an authentication cookie is read using JavaScript before the post is made, JavaScript's stricter (and more correct) cross-domain rules will be applied. If the server requires requests to contain the value of the authentication cookie in the body of POST requests or the URL of dangerous GET requests, then the request must have come from a trusted domain, since other domains are unable to read cookies from the trusting domain. On the other hand, this method forces users to enable JavaScript.

They are suggesting that you build your HTML form in a way that at the time the form is posted, javascript gets called which reads the session cookie and places that cookie in the body of the html (or part of the form post payload as a normal form element). The server would then verify that the session id is valid in both the session cookie and the html body (or form post payload). If the CSRF attack code was hosted on a different server than the victim server, this "session cookie transfer to body" code would fail due to the cross domain rules. Not an unreasonable defense!

The scenario for CSRF defense would not work in the face of HTTPOnly. BUT - I can circumvent this defense by placing CSRF attack code on a cross-site that reads the cookies out of an XHR header (since they are not httponly for this defense), and adds it to the post manually. This lets an attacker circumvent double click defense!

Now, as browsers handling of XHR matures, the validity of this claim gets stronger (the claim that double-click defense is good).

IE lets you read cookies out of XHR request headers (that are not httponly) which would let an attacker circumvent the double-cookie defense like I described above. FireFox is vulnerable to this defense too, prior to 3.0.0.6. Starting with FireFox 3.0.0.6, cookies - any cookies - are no longer included in Firefox XHR response headers.

HTTPOnly will block this defense from working, since it depends on JavaScript reading cookie in the context of the current domain.

In a world where you can no longer read ANY cookies from XHR headers, AND httponly is in widespread use - I can see an argument to not use HTTPOnly depending on the risk - which is why implementers for server side products should provide options to disable HTTPOnly! :)

4 comments:

Jim Manico said...

(From Bil Corry)

I agree, HTTPOnly should be optional, there are cases where you want to manipulate the cookie using JavaScript.

The double-submit cookie method is a crap way to protect against CSRF -- if they absolutely must use the double-submit cookie method, then set two cookies, the session cookie is HTTPOnly, and the CSRF cookie isn't. They can still use the CSRF cookie for CSRF protection and the session cookie (which provides authentication) can be kept safely from XSS/XHR/etc.

Simo Salminen said...

Why you think it is crap? What is the best way, and why?

Jim Manico said...

I prefer to use a per-session CSRF token. Per http://www.owasp.org/index.php/Cross-Site_Request_Forgery

"Add a per-request nonce to URL and all forms in addition to the standard session. This is also referred to as "form keys". Many frameworks (ex, Drupal.org 4.7.4+) either have or are starting to include this type of protection "built-in" to every form so the programmer does not need to code this protection manually."

Anonymous said...

As per you, the attacker has to place the js on a cross-site for the attack to succeed. What exactly do you mean by cross-site?