7

I've seen several implentations of CSRF tokens:

  • The first one uses randomly generated CSRF tokens which uses a cryptographic strong random generator to generate the token.
  • The second implementation I found uses HMAC which encrypts the session id with secret key stored in the server side config.
  • The third implentation I saw uses a combination of both, a secret key stored in the server side config is used to HMAC a random generated value

The second one does not require state to be stored server side (which is ideal in case of clustering).

I'm wondering what the benefit is between the first and third implementation.

  • An unkeyed hash of the session token should work as well. – CodesInChaos Feb 25 '14 at 16:05
  • I can't even see an attack against using the session token itself. – CodesInChaos Feb 25 '14 at 16:06
  • If the session token is in the markup somewhere, then XSS can trivially access it. – Slicedpan Feb 25 '14 at 16:27
  • @Slicedpan the session token isn't present in a readable for, but HMACed so that wouldn't be an issue. – Lucas Kauffman Feb 25 '14 at 16:30
  • It doesn't need to be, if someone can access the markup, they can send that token elsewhere and use it to authenticate as the user, or am I missing something here? – Slicedpan Feb 25 '14 at 16:34
8

The first one uses randomly generated CSRF tokens which uses a cryptographic strong random generator to generate the token.

This is ideal. In this case, the token is an absolutely unpredictable opaque block with no significance outside its intended context.

The second implementation I found uses HMAC which encrypts the session id with secret key stored in the server side config.

This is simpler to implement. Presumably session IDs are already being generated, so nothing additional needs to be persisted. Since no further storage is necessary, it could be that this mechanism may be implementable in situations where a random token couldn't be worked in to a legacy design. This is a relatively elegant workaround. Assuming the secret key doesn't become known to the attacker, the token shouldn't be reproducible outside the server.

The third implentation I saw uses a combination of both, a secret key stored in the server side config is used to HMAC a random generated value

This is a little silly. Presumably driven by the fact that a an HMAC is a security-related concept, the author attempts to add security to his design by including something security-related. A sort of magic security talisman. Presumably it's no worse than using the random number alone, but it's certainly no better. Unless you count the warm fuzzy feeling you get from using HMAC in your security implementation.

It is, however, a reasonable work-around if you have a poor RNG, though in that case I would probably mix the session ID or something similar in there before hashing so that you're guaranteed that the number you hash in unique.

  • 1
    I disagree that randomness is the ideal. A better option is to have a HMAC of some useful information, like username and timestamp (OWASP also suggests a random nonce and the current application action), with a secret key on the server. That way, you have an unforgeable token without requiring server-side state, plus since you have the timestamp, you can easily refresh and/or reject old tokens. – ThrawnCA Apr 4 at 6:11
-1

I know that asp.net MVC 3/4 uses a method similar to 2. The problem I find with that approach is that there is one CSRF token for the session, as opposed to by form. So for example, if I obtain the CSRF token once, that token is valid for any form post during the course of the session. When testing with a tool such as ZAP, one request gives me the token which I can then reuse at my pleasure. Further to this, the token has to be written somewhere to the HTML page (it is not stored in a cookie, for example) and then could be easily read by an attacker looking for the specific string.

I like the idea of 1/3. The randomness provides security on a by form/call basis, as opposed to one per session. It can also be used to prevent multiple posts of the same form. This would be useful in a transactional system where you would want to ensure that a submit only occurs once. When the server receives the first submit, it invalidates the token. The next submit would fail. The attacker now has to get a hold of a token and use it before the user does.

I can see your point regarding clustering / load balancing, but most load balancers can/will forward requests from the same session to the same backend host.

  • 1
    You don't need a token per form, only per user session. If an attacker gets hold of this token all bets are off anyway - your system has already been compromised. – SilverlightFox Feb 25 '14 at 20:50
  • Sorry, disagree. See owasp.org/index.php/… Specifically: "To further enhance the security of this proposed design, consider randomizing the CSRF token parameter name and or value for each request. Implementing this approach results in the generation of per-request tokens as opposed to per-session tokens" – CtrlDot Feb 25 '14 at 20:58
  • This approach has to be designed into the system from the ground up. You can't just drop in a per form token and expect extra security - the attacker would just execute another GET request and get the new token. This would have to be implemented where each request (even navigation) sends a POST request and any attempt to use the back button logs the user out. Only then you can regenerate the token for each request (as each request is then a POST that can only be generated from the previous POST). Some banking applications employ this approach. – SilverlightFox Feb 25 '14 at 21:44
  • @SilverlightFox I agree with that, it has to be designed up front and there are cons to the approach. – CtrlDot Feb 25 '14 at 22:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.