0

Alright here is my proposal:

Use a hash of a login token as the anti-CSRF token.

Why this is a good idea?

  • Prevents having to store anything extra on the client, the server, and less network traffic as we don't need to transfer an additional cookie on every request
  • All the benefits of cookie based CSRF token
  • Login token still can't be accessed by JS (Its a non-reversible hash so we output the hashed login cookie in a meta tag, AJAX can still use it without exposing the login token
  • If login token is indeed unique per session (even between the same users) then each csrf token will be unique per session (minus collisions)

Is there any security problems I am missing? Obviously this would only work for pages where the user is logged in. But that shouldn't be an issue.

Btw by "login token", I mean a securely pseudorandom string that is stored on the server and on the client in the form of a cookie that allows the server to authenticate a user without them having to enter their password each time the page changes.

Ok so it was brought up that by using this method you are decreasing security ever so slightly because the hash is based off of the login token and you could brute force to find the login token. Even tho I think this is basically impossible because of how hashes work I propose the following solution. Split the login token into 4 parts, hash the 3rd and 4th using the 2nd as a salt. This prevent the use of rainbow tables and even if an attacker somehow brute forces, they will only have 3/4th of login token. Also, the salt doesnt need to be prepended to the csrf token itself because it can be derived using the login token.

2

Sure.

This is actually one of my preferred approaches. It makes the strength of your CSRF protection wholly dependent on the strength of your session token security, but session takeover strictly dominates CSRF in impact anyhow. The hashing means you can leave your session token in an HttpOnly cookie and not expose the session to JavaScript in any way.

However, drop everything in your last paragraph. Hashing only part of the token is strictly weaker than hashing the entire token. If you're hashing only part of the token, then brute-forcing that part is much easier (because it's shorter than the full token), and once you have a match you can not only launch CSRF attacks, you can also easily brute-force the last quarter (after all, you already brute-forced a string 3x as long) and take over the session. Salting is also meaningless in this context; the only value of a salt is to add entropy to the terribly predictable / repeatable strings people use as passwords, and if your token is fully random than what you propose would simply be taking out some amount of entropy and then putting it right back in, to no net benefit at all. You can't compute a rainbow table over possible 128-bit random token; every CPU and GPU on the planet working together would still take might-as-well-be-forever, and you couldn't actually store the table (even if some magical supercomputer could generate it) even if you turned every atom of the Earth into storage.

If you want a little bit of "feel good" security, you can HMAC the session token rather than just doing a simple hash. This is pretty pointless, though. Assuming the session token is already not at risk of brute force (because, if it is, you have WAY bigger problems than CSRF), any secure hash (I recommend something from the SHA2 or SHA3 family) is fine.

By the way, this works fine even with session token types other than the "secure random string stored in a cookie" approach. That approach has some of the problems that things like double-submit cookies try to get away from (it requires storing state on the server for each session, load balancing interferes with or at least complicates it, etc.) but this idea also works with things like JWTs. The main downside of the approach is if the session token changes (say, because a JWT was refreshed), the CSRF token changes, so you need to be careful not to reject valid requests for that reason.

Also, for what it's worth, login CSRF protection is a decent idea, on at least some sites. Anywhere a user will upload data that only they are to be allowed to see, login CSRF is a risk. Imagine a tax-filing webapp where you put in your highly-sensitive data into what you think is your own session, but somebody sneakily login-CSRFed your session to a session they have the password to. Then, after you've completed your tax return, the attacker logs in to the same account (it's theirs, after all) and downloads your returns.

  • About my last paragraph. While true if you brute forced 3/4ths, the last 4th should be easy, however the last forth could not be done offline which would significantly increase the time it would take. – JBis Oct 18 '19 at 3:07
  • @JBis Why could it not be done offline? An attacker has everything she needs to do the cracking. – Tom K. Oct 18 '19 at 11:16
  • @TomK. 3/4ths could be done offline because the attacker would have a hash of 3/4th, but the last fourth is not included in the hash so it could not be done offline. – JBis Oct 18 '19 at 11:17
  • @JBis The problem is not online vs. offline cracking. The problem is that, by splitting the hash, you can try brute-forcing two shorter strings, which is vastly easier than brute-forcing the whole thing at once (a common flaw of early password hashing). The time to brute force a random string is exponential to the length of the string. Brute-forcing 2^128 (128 bits) possibilities takes billions of times the length of 2^96 possibilities followed by 2^32 possibilities. One you have the first 96 bits, you're max 4 billion guesses from the rest; a botnet could try them all, online, in minutes. – CBHacking Oct 18 '19 at 17:27
  • @CBHacking What hashing algorithm do you suggest? – JBis Oct 18 '19 at 19:53

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.