107

In many tutorials and guides I see that a CSRF token should be refreshed per request. My question is why do I have to do this? Isn't a single CSRF token per session much easier than generating one per request and keeping track of the ones requested?

Generating the token on a per-request basis doesn't seem to improve security beyond what a per-session token would already do. The only argument seems to be XSS protection, but this doesn't apply as when you have a XSS vulnerability the script could read out new tokens anyway.

What are the benefits of generating new tokens per request?

Bob Aman
  • 103
  • 3
Philipp Gayret
  • 1,383
  • 2
  • 10
  • 14

8 Answers8

125

For the reasons already discussed, it is not necessary to generate a new token per request. It brings almost zero security advantage, and it costs you in terms of usability: with only one token valid at once, the user will not be able to navigate the webapp normally. For example if they hit the 'back' button and submit the form with new values, the submission will fail, and likely greet them with some hostile error message. If they try to open a resource in a second tab, they'll find the session randomly breaks in one or both tabs. It is usually not worth maiming your application's usability to satisfy this pointless requirement.

There is one place where it is worth issuing a new CSRF token, though: on principal-change inside a session. That is, primarily, at login. This is to prevent a session fixation attack leading to a CSRF attack possibility.

For example: attacker accesses the site and generates a new session. They take the session ID and inject it into a victim's browser (eg via writing cookie from a vulnerable neighbour domain, or using another vulnerability like jsessionid URLs), and also inject the CSRF token into a form in the victim's browser. They wait for the victim to log in with that form, and then use another form post to get the victim to perform an action with the still-live CSRF token.

To prevent this, invalidate the CSRF token and issue a new one in the places (like login) that you're already doing the same to the session ID to prevent session fixation attacks.

bobince
  • 12,494
  • 1
  • 26
  • 42
  • Is this advice still valid now that BREACH attacks are a thing? – millerdev Mar 15 '17 at 01:08
  • 3
    BREACH attacks are supposed to be solved at a different layer (by disabling application data compression AND TLS compression), so the answer is: you shouldn't worry about the BREACH attack unless you're setting up TLS or the HTTP server – David 天宇 Wong Jan 29 '18 at 00:44
  • @millerdev BREACH attack can be mitigated by applying a random mask to the csrf token on each request while keeping the actual token value unchanged. This prevents BREACH attack as the random mask makes it impossible to guess and also maintains usability because the token's secret value is still the same. – xyres May 06 '21 at 05:47
28

Overview. The standard advice is to use a unique CSRF token that is unique for each request. Why? Because a per-request token is a bit more resilient to certain kinds of implementation errors than a per-session token. This makes per-request tokens arguably the best choice for new web application development. Also, no security auditor is going to hassle you about using a per-request CSRF token.

If you're a web application developer, this is all you need to know, and you can stop reading here. But if you're a security expert wondering about the detailed rationale behind this advice, or wondering about just how great the risk is if you do use a per-session token, read on....


Digging in a bit deeper. The truth is that, if you don't have any other vulnerabilities in your web site, a single CSRF token per session is OK. There's no reason why you necessarily have to generate a fresh CSRF token per request.

This is demonstrated by the fact that you'll also find reputable security experts who say that another reasonable way to defend against CSRF is to use cookie double-submission: in other words, you use some client-side Javascript which computes a hash of the session cookie and adds that to each POST request, treating the hash as the CSRF token. You can see that this essentially generates on-the-fly a CSRF token that is the same for the entire session.

Of course, I know the argument why some people might recommend generating a new CSRF token for every request. They are thinking, if you also have a XSS vulnerability on your website, then if you use a single CSRF token per session it will be easy to use XSS to recover the CSRF token, whereas if you generate a new CSRF token per request, it will take more work to recover the CSRF token. Personally, I don't find this a terribly compelling argument. If you have a XSS vulnerability on your site, it's still possible to recover CSRF tokens even if you generate a new CSRF token for every request, it just takes a few extra lines of malicious Javascript. Either way, if you have a XSS vulnerability on your site and you face a serious, knowledgeable attacker, it's hard to guarantee security, no matter how you generate your CSRF tokens.

Overall, it can't hurt to generate a new CSRF token for every request. And maybe it's better to do it that way, just to get security auditors off your back. But if you already have a legacy application that uses a single CSRF token for the entire session, spending the money to convert it to generate a new CSRF token for each request probably wouldn't be super-high on my priority list: I bet I could find some other uses for that money and developer energy that would improve security even more.

Chris Owens
  • 103
  • 4
D.W.
  • 98,420
  • 30
  • 267
  • 572
  • I wouldnt call them "reputable security experts" if they recommend double cookie submission... XSS is not the only issue at hand for that. OWASP has a good rundown on this... – AviD Oct 21 '12 at 11:15
  • @AviD, double submit cookies is perfectly fine. I've yet to see any proof that this approach is substantially more vulnerable than any other approach. Every technique has its vulnerabilities. This one is no different. – Gili Jun 27 '14 at 03:35
  • 5
    @Gili the problem with double-submit cookies is that this typically is referring to the normal, already-existing session cookie - and this should not be accessible to JavaScript (e.g. using the `HttpOnly` flag). Using this technique may prevent the CSRF attack, but would open the session cookie to other issues, such as making it more vulnerable to possible XSS vulnerabilities. There are techniques which work just fine, without causing other, separate vulnerabilities. – AviD Jun 27 '14 at 08:14
  • 1
    @AviD, as mentioned in http://security.stackexchange.com/q/61110/5002 OWASP instructs developers to use a separate cookie for the CSRF token precisely for this reason. You can keep the `HttpOnly` flag on the session cookie. – Gili Jun 27 '14 at 08:24
  • @Gili yes, that's exactly the point. – AviD Jun 27 '14 at 15:43
  • @AviD, sorry I don't understand your point. You said that double-submit cookies forces you to remove the `HttpOnly` flag from the session cookie, but I just explained that this is not the case (you can use a separate cookie for the double-submit cookies token). Doesn't this invalidate your original complaint? – Gili Jun 27 '14 at 17:12
  • 1
    @Gili, re-read AviD's comments. Don't miss his use of the word "typically". Double-cookie submission is typically understood to mean re-using the session cookie. If someone is recommending double-cookie submission, and they don't have some explicit disclaimers to the contrary, that means they are recommending re-using the session cookie. I think AviD covered this with his comments above. – D.W. Jun 27 '14 at 17:15
  • Fair enough. PS: On a related note, http://security.stackexchange.com/a/43550/5002 questions the value of `HttpOnly` against XSS attacks. – Gili Jun 27 '14 at 17:23
  • @Gili, yup, I know. :-) I just posted an answer on the question you linked to, and also linked to the same discussion about `HttpOnly`. Thanks for the pointer and the discussion! – D.W. Jun 27 '14 at 17:43
  • @Gili yes, exactly as D.W. said, that was my intention exactly. – AviD Jun 28 '14 at 21:08
  • @AviD, I'm glad we're both on the same page. Thanks for the clarification. – Gili Jun 29 '14 at 19:35
  • 4
    "it can't hurt to generate a new CSRF token for every request", it hurts usability(?) – pinkpanther May 24 '16 at 20:44
  • CSRF token for every request can be refreshed but you have to take care of Ajax calls. In a way it's tedious process but Ajax call can be updated. – Saurabh Feb 05 '20 at 14:10
15

XSS can be used to read a CSRF token, even if it is a single submit token, that is child's play. Its likely that this recommendation of a single submit token came from someone who doesn't understand CSRF.

The only reason to use a "single submit token" is if you want to prevent the user from accidentally clicking submit twice. A good use of this is to prevent the user from clicking "checkout" twice and accidentally charging the customer twice.

A CAPTCHA or asking for the users current password can be used as an anti-csrf measure that cannot be bypassed by XSS.

I recommend reading the CSRF Prevention Cheat Sheet.

jobo3208
  • 101
  • 2
rook
  • 46,916
  • 10
  • 92
  • 181
  • 4
    I don't see how a CAPTCHA or entering the password would be secure in the face of XSS. It just forces the attacker to jump through a few additional hoops. – CodesInChaos Oct 20 '12 at 19:00
  • @CodesInChaos the attacker would have to know the password, and then its a moot point. – rook Oct 20 '12 at 19:53
  • 1
    If the user enters the password at some point after the xss the attacker can probably steal it. So re-entering the password helps a bit, but not much. – CodesInChaos Oct 20 '12 at 20:12
  • @CodesInChaos That works fine on paper, but this proposed attack is considerably less likely to succeed in a real world scenario. – rook Oct 20 '12 at 20:28
  • 2
    @CodesInChaos you are correct that a CAPTCHA would be irrelevant to this. On the other hand, reauthentication (selectively on sensitive actions) is one of the best solutions for CSRF, and should be used more. Also see Schneier's discussion about "transaction authentication", which is similar, though not identical. – AviD Oct 21 '12 at 11:12
  • Single-use tokens have even more benefits (at least for mission-critical operations): They add security against [replay attacks](http://en.wikipedia.org/wiki/Replay_attack). – Domi May 01 '15 at 12:29
  • @Domi It depends how they got the token in the first place. If it with XSS, or over an insecure channel, the a rolling token wouldn't matter. – rook May 01 '15 at 15:38
  • They still add security against replay attacks, given there is no XSS. – Domi May 01 '15 at 16:08
6

If the token is the same across the entire session, it may be possible for an attacker to leak a token from one page and use it for a different action.

For example, you could use an iframe to load a page, then extract the token using an XSS vulnerability. From there, you could use that token to submit a password change form

Using a per-request token instead of a session-wide one makes it more difficult, but it doesn't prevent CSRF. An attacker can simply leverage an XSS to read the token from the page, then fire it off. However, if the token is global rather than restricted to that individual page, an attacker can target any page to steal the token. Using separate tokens for each request makes this much harder.

Polynomial
  • 132,208
  • 43
  • 298
  • 379
  • 7
    Theres no way someone can extract a anything from iframe, this would break the [same origin policy](http://en.wikipedia.org/wiki/Same_origin_policy) – Philipp Gayret Oct 20 '12 at 14:46
  • @SkPhilipp Sorry, I meant to say via XSS. – Polynomial Oct 20 '12 at 15:18
  • 1
    Using a XSS should be possible to extract token even if refreshed at every request. Am I right? – Emilio Oct 20 '12 at 16:05
  • 3
    Yes, via XSS you could then load an iframe to a password change form, and you could extract that token, generating new tokens wouldn't make that any secure if you have an XSS vulnerability. – Philipp Gayret Oct 20 '12 at 17:41
  • -1 I'm sorry but i don't want people to get the idea that if they use a single submit token they are magically protected against XSS, because that is most untrue. If a user can do it in a web browser, then xss can do it in a web browser. – rook Oct 20 '12 at 18:25
  • 1
    @Rook Huh? I never said using a single token was good... – Polynomial Oct 21 '12 at 11:56
  • 5
    If you have an XSS vulnerability you can use an XHR to read any page and submit any request. Having a different token on each page doesn't help. – rook Oct 21 '12 at 17:37
  • @Rook I'm not saying it solves the problem entirely, but it does make it harder if you use individual tokens and lock them to specific requests. I can see why you're worried the answer would give the wrong impression, though. – Polynomial Oct 22 '12 at 05:57
3

Further to the other answers, it might be wise to refresh the token too if your server is susceptible to the BREACH attack.

This requires the following three conditions:

  • Be served from a server that uses HTTP-level compression
  • Reflect user-input in HTTP response bodies
  • Reflect a secret (such as a CSRF token) in HTTP response bodies

To mitigate BREACH you would need to refresh the CSRF token on the GET request that loads a form to invalidate all previous tokens. This way, a MITM (Man-In-The-Middle) creating additional requests to discover the token in the page will get a different token each time. This does mean that the real user will not be able to submit the form in a MITM situation.

Of course you need the other two conditions to hold true also. It would probably be easier to maintain a CSRF token per session and disable HTTP-level compression for any pages that serve forms.

SilverlightFox
  • 33,408
  • 6
  • 67
  • 178
2

It isn't very known fact, but normal string comparison is vulnerable to timing attacks (such as this one. Long story short, normal string comparison operations (== or ===) will compare two strings character-by character from left to right and return false once they've encountered any character that's not equal at a given position in both strings. This gives a minuscule difference in timing that's been proven to be detectable.

By using a timing attack to try every possible character for each position, it is possible to work out what the actual token is. By creating a new token every time a request with a token is submitted, this attack can be prevented.

Of course, this only works if you also recreate the token if an invalid token has been submitted, which may be undesirable. Therefore, you're better off fixing this by using a time-insensitive string comparison function such as this one.

user2428118
  • 2,768
  • 16
  • 23
  • Okay, but i have to note in the examples and paper you've listed a theoretical attacker could measure the CPU clock time very precisely. The machine was under no other load, and many languages use precalculated hashcodes for string comparison before performing a character by character check. – Philipp Gayret Jul 22 '15 at 10:10
  • 1
    Constant time compares can and should be used to mitigate this (loop over all chars and xor a difference flag). – eckes Jan 14 '16 at 21:46
0

One reason for wanting to change the CSRF token per request is to mitigate compression leaking of the token. What I mean by that is that if the attacker Eve can inject data on a page containing the token where the page is sent compressed Eve can then guess at the first character of the string receiving a smaller dataset for the page knowing she guessed right then go on to the next character.

This is similar to a timing attack.

At the moment there is no reason (that I know of) to change the token if it is only sent in the HTTP headers.

Another method is to change the token as soon as a failed request is discovered, but this could have problems with the user not being able to submit any form.

edruid
  • 571
  • 1
  • 4
  • 11
-1

If the same token is used for the entire session then then there is probability of attacker can hijack the token using XSS and use the victim's session to do some malicious activities like changing the password .

They can cange passwords by lodaing an iframe into the site you are using.

So it is better to use one token per request to avoid the attacker to gain access to that token.

Bhuvanesh
  • 87
  • 1
  • 5
  • 2
    An attacker using XSS can get access to new tokens, this is what the whole question is about. See also the comments on http://security.stackexchange.com/a/22904/15195 – Philipp Gayret Jul 28 '15 at 09:35