Technical Insight

Raising the CSRF Bar

For years, we at WhiteHat have been recommending Tokenization as the number one protection from Cross Site Request Forgery (CSRF). Just having a token is not enough, of course, as it must be cryptographically strong, significantly random, and properly validated on the server. Can’t stress that last point enough as the first thing I try when I see a CSRF token is to empty the value out and see if the form submit is accepted as valid.

Historically the bar for “good enough” when it comes to CSRF tokens was if the token was changed at least per session.

For example: A user logs in and a token is generated & attached to their authenticated session. That token is used for that user for all sensitive/administrative forms that are to be protected against CSRF. As long as when the user is logged out and logged back in they received a new token and the old one was invalidated, that met the bar for “good enough.”

Not anymore.

Thanks to some fellow security researchers who are much smarter than I when it comes to crypto chops, (Angelo Prado, Neal Harris, and Yoel Gluck), and their latest attack on SSL (which they dubbed BREACH), that no longer suffices.

BREACH is an attack on HTTP Response compression algorithms, like gzip, which are very popular. Make your giant HTTP responses smaller, which makes them faster for your user? No brainer. Well now, thanks to the BREACH attack, within around 1000 requests an attacker can pull sensitive SSL-encrypted information from HTTP Responses — sensitive information such as… CSRF Tokens!

The bar must be raised. We now no longer allow Tokens to stay the same for an entire session if response compression is enabled. In order to combat this, CSRF Tokens need to be generated for every request/response. This way they can not be stolen by making 1000 requests against a consistent token.

TL;DR

  • Old “good enough” – CSRF Tokens unique per session
  • BREACH (BlackHat 2013)
  • New “good enough” – CSRF Tokens must be unique per request if HTTP Response compression is being used.
Tags: csrf, web application security, web security
  • http://www.stephenduncanjr.com Stephen Duncan Jr

    It is interesting using CSRF to protect pages with other sensitive information is often described for mitigating BREACH, and yet I had not seen previous discussion of the idea the CSRF token is going to be a very common piece of sensitive information that can be attacked with BREACH (articles usually focused on PII). However, I do have a concern with your suggested course of action.

    The main reason for per session CSRF tokens is usability: a user may open multiple CSRF protected resources in multiple tabs, or via the back/forward button, and a per-request CSRF token will now reject valid submissions (also documented in the synchronizer token pattern here: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet )

    Since the BREACH attack can be mitigated by including random content in your response, perhaps adding that in standard is a good idea. I understand this only makes the attack more expensive, rather than preventing it entirely, so if we went with this approach, it would be necessary to protect the most sensitive actions with password re-entry rather than just CSRF protection (which is already true, but might lead us to re-categorize some actions).

    A compromise occurs to me that might be better. We should generate a unique CSRF token per page-request, but store all (up to some reasonable limit to manage the tradeoffs between memory, security, and usability; I’d probably default to 100 in a framework to err on the side of usability) to validate against. By generating a unique CSRF, we thwart the BREACH attack (though only against CSRF tokens; other sensitive information must have it’s own considerations), but by allowing multiple CSRF tokens in the session to stay valid (though they should only be allowed to be used once, of course), we support multiple tab & back/forward browsing usability.

    • Maurina Venturelli

      Hi Stephen,

      Here’s Matt’s reply:

      Completely agree. The course by which you generate your per request CSRF Tokens is up to you for usability sake. Unique by request CSRF tokens have always been the best solution and are very widely used today. We just always considered a by session one good enough until BREACH, which makes them fairly easy to steal out of the response.

      I’m not suggesting this is a solution to BREACH as a whole, but it will protect the tokens themselves. Building up a pool server side of valid tokens is a perfectly valid way to approach this but also might not work for certain implementations. No matter which way you slice it, leaving the token the same for too long a period of requests will expose it to BREACH.

      Thanks for the input, great points.
      Matt

      • http://www.stephenduncanjr.com Stephen Duncan Jr

        Matt says “Unique by request CSRF tokens have always been the best solution and are very widely used today.” I looked at Spring Security (for Java), and Ruby on Rails, and both seem to unique-by-session CSRF tokens, and between those two, that has to cover a significant portion of the web applications being developed out there. Can you give some examples of frameworks that use unique-by-request CSRF tokens?

  • Justin Barron

    What about just requiring the token to change every 999 requests? 😉

    It’s good to see the “good enough” bar being raised in this area, and with the exponentially increasing capabilities and relative cheapness of hardware, using the “we have limited resources” excuse is becoming a less and less acceptable reason to not use per-request tokens. And we, the collective industry “we”, will have to continue raising all sorts of bars as technology changes and new attacks are discovered.

  • Vikram

    I think Rails already does that – generates a new CSRF token for each request.