Thursday, June 20, 2013

Cookie Forcing protection made easy

I wrote a post about CSRF tool and readers noticed an intentional mistake in it — storing a token in a plain cookie can be exploited with cookie forcing (like cookie tossing we saw on github, but works everywhere). TL;DR With MITM attackers can replace or expire any cookie (write-only)

Actually I don't think it's mistake in CSRF protection design, I still think problem is about horrible cookies design. But we got to deal with current situation, and taking into account this feature I came up to concise and effective protection.

At first glance it might look ugly. But web is ugly so it's OK.

Step 1. We simply put csrf_token value into session. Wait, we do not store it in database, because it's pointless. We do not store it in signed cookie either like Rails do (this is also overwork).
I propose to literally store csrf_token in session cookie:
sid=123qweMySeSsIon--321csRFtoKeN
You only need a middleware on top of the stack slicing the token after --.

Step 2. Attacker still can fixate the whole session cookie value (sid + csrf token). So always refresh csrf_token after login to make sure csrf_token wasn't fixated.

Can you see anything simpler than this trick? I guess everything using two separate cookies will require signatures and cryptography with server secret. Too much work for a design mistake W3C made.

Although CSRF protection on its own is not popular, cookie forcing protection is way less popular — don't be surprised how many websites/frameworks are vulnerable. How to check: it is vulnerable if you can replace csrf_token cookie (use Edit This Cookie) not breaking session or csrf_token remains same after login.

For example Django framework (csrftoken cookie is not integrated with session), twitter (doesn't refresh authenticity_token after log in, so it can be fixated), etc.

Google Reader is dead, make sure to follow me on another website.

21 comments:

  1. Google+ is much better than Twitter. Here is your page: https://plus.google.com/110421481014101227624/posts - for those who thinks the same :)

    ReplyDelete
  2. If it's not too stupid question, please, explain what the difference between storing token in separate cookie and in session cookie? (if we always refreshing token)

    ReplyDelete
    Replies
    1. because when you store it separately attacker can use Cookie Forcing and change csrf token not changing session cookie, simply saying inject a new value.
      If these values are tied (same cookie) he cant do so

      Delete
    2. why can't he do that? i still don't get it....because you also say:

      "Attacker still can fixate the whole session cookie value (sid + csrf token). So always refresh csrf_token after login to make sure csrf_token wasn't fixated."

      so all i understand from this is that besides refreshing the session id you also have to refresh the CSRF cookie after login......

      Delete
    3. yes, id must also be refreshed, you are right

      Delete
    4. it's still not clear. why can't attacker do cookie forcing if csrf + session are in the same cookie?

      Delete
    5. because he cannot change token only, he also must know session value to change cookie

      Delete
  3. Sorry for disturbing you again. Can you please read on this page http://docs.angularjs.org/api/ng.$http part about XSRF and give your opinion, is it safe enough or not.

    ReplyDelete
    Replies
    1. i think it's weird

      >We recommend that the token is a digest of your site's authentication cookie with a salt for added security.
      if salt means session secret then stealing the secret we can guess someone's token.
      but it looks close to integrity because of signing

      Delete
  4. So client-side should then parse cookie name to receive token and send in http-header received token with POST request?

    ReplyDelete
    Replies
    1. Because otherwise I don't see how can I validate token on server side.

      Delete
    2. no, csrf token should not be parsed from the cookie, it should be ALSO stored in , say, meta tag in the header

      Delete
    3. It's much less convenient way, when HTML are static pages, supposed to be filled by results of XHR-requests (AngularJS it's exact example of this variant).
      Also, it's just unusable variant for REST APIs.

      Delete
    4. CSRF can be obtained with /token.json for example. It must be stored in httponly cookie

      Delete
    5. after more than a year, has your opinion changed about this method?

      If I put the csrf token in meta, then the browser can not cache it. Ugh! so ugly. but the web is ugly, so it's OK!

      Delete
  5. Hi, thanks for sharing your ideas :)

    A stupid question,
    have you ever heard of Synchronizer Token Pattern?

    https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29_Prevention_Cheat_Sheet

    In my opinion your approach here is quite similar from some points of view, do you think that Synchronizer Token Pattern is not good enough?
    Maybe you wrote about that in another post, if it is so please let me know.

    ReplyDelete
    Replies
    1. csrf is synchronizer pattern. cookie forcing is another attack and i updated CSRF design to make it secure by default from all attacks. Nothing changed generally, it's cosmetic trick

      Delete
    2. Thank you for your reply.

      I clearly misunderstood the point here :)

      Delete
  6. Just to clarify - we assume that despite using HTTPS, a MITM attack has write-only access to the target's cookies - IE they can read them and not write them?

    So the idea being, that they can simply replace an individual cookie for CSRF Token, but if it's part of the session ID, they cannot, because they'd have to reconstruct it from the session ID which requires write access?

    Thanks

    ReplyDelete
    Replies
    1. exactly, to replace SID+TOKEN cookie you will must to know SID too, because values are tied into a single cookie

      Delete