CSRF Security – How Frequent Should the Token Updation in CSRF Security Be?

patterns-and-practicesprogramming practicesSecurityweb-development

To start with the background, this post is what Jeff Atwood says about CSRF tokens. In this very page, he goes on to say:

An even stronger, albeit more complex, prevention method is to
leverage server state — to generate (and track, with timeout) a
unique random key for every single HTML FORM you send down to the
client. We use a variant of this method on Stack Overflow with great
success.

But in this post itself, Jeff never remarks about when and how the tokens should be updated.

I was using a similar technique in a web-app I was working on. It works like this:

  1. Whenever the user will POST data to my server, a csrf token is sent along.
  2. This CSRF token is stored in a cryptographically strong cookie in user's session.
  3. If the token is valid, the user's request is processed and vice-versa.
  4. If the request is valid, discard the old token on server side and create a new token. The response from server contains a new csrf token to be used in the next request. The old token on all the forms on a page is updated with the new one so that the next request is processed properly.

Is it wise to update the tokens after ever POST request or should the updation be done only whenever the user makes a GET request and keep the same token till the next GET request is made?

Best Answer

The main point of a CSRF token is that it can't have been sent from another site. So therefore it (a) can't be predicted or detected by an attacker, and (b) is not automatically attached to a request the way a cookie is.

So theoretically if a CSRF token is never disclosed to third parties, again theoretically, you don't have to expire them at all. But then you run the risk of your token getting "leaked" somehow. So your expiry period really should be short enough to combat the prospect of a token getting out and being used against your user.

There aren't really any guidelines, but a good solid techique is to auto-generate a new token on EVERY request which embeds a signed timecode, and then accept tokens up to a certain age.

A sample function might be:

concat(current_time,salt,sha256_sum(concat(salt,userid,current_time,secret_string)))

The token contains timing information and a salt, but also contains a signature which can't be forged and which is tied to the userid.

Then you can define your own expiry interval -- an hour, a day, 2 hours. Whatever. The interval in this case isn't tied to the token, so you're free to set expiry rules however you want to.

At the very least, though, CSRF tokens should expire when the login session expires or when the user logs out. There's no expectation by the user that a form that you brought up BEFORE you logged out will continue to work AFTER you log back in again.