Is there any standard length of the token which should be used while generating the random tokens? Should we use the same standard which we use for generating Session IDs?
3 Answers
I would consider a 128 bits of entropy in a token to be the de-facto standard. OWASP and CWE both recommend this as a minimum. 20 characters of Base64 (capable of 120 bits) is also handy for something in the URL. I would also note that in many cases poor seeding for those tokens creates problems. For one bit of reference, see the (kind of tastelessly decorated, but very informative) slides from http://samy.pl/bh10/.
Make sure you choose your entropy source well.
-
2I think the 160 bit tokens you mentioned in the first version of your posting are so common because they are a nice round number of 20 characters. (Although it should be noted that the bit size of token is not equal to the amount of entropy dune to the limited range of printable characters). Commented Sep 9, 2011 at 6:08
-
Should we use the same standards which we use for generating Session IDs for generating CSRF tokens as well? Just curious.. Thanks Jeff for Samy's very informative presentation. Commented Sep 9, 2011 at 6:39
-
1
-
@Hendrik Base64 * 20 chars = 120 bits of entropy. I'll modify my answer again to be clearer... and I think 120 is "close enough" to be ok.– Jeff Ferland ♦Commented Sep 9, 2011 at 12:46
This is an old question, but I've had occasion to look into this question and decided to at least look into what some and CSRF libraries use by default and my results are as follows:
Django : 32 random characters from the set [a-zA-Z0-9] : 190.53 bits of entropy
Ruby on Rails : 32 bytes of entropy (encoded as base64) : 256 bits of entropy
Spring Security : UUID4 (actually, this seems to use a PRNG, not an RNG, if I'm not mistaken) : 122 bits of entropy
OSASP PHP CSRF Guard (https://www.owasp.org/index.php/PHP_CSRF_Guard) : 128 characters from the set [a-z0-9] : 661.75 bits of entropy
OWASP J2EE CSRF Guard : 32 characters in the set [A-Z0-9] : 165.44 bits of entropy
Oracle ATG version 10.1.1 : a standard Java "long" encoded using ascii base 10: 64 bits of entropy
Note that my sample is heavily biased toward frameworks of which I can access the source code and frameworks I'm familiar with.
I've specifically tried to find frameworks which use 64 bits or less of entropy to try and justify why ATG would use a standard Java "long" and have been unsuccessful, so my conclusion is that 64 bits is probably too short.
That said, assuming an attacker can do 100,000 requests per second, it should take around 2.93 million years on average to brute force a 64-bit CSRF token. (And there shouldn't be more than one token in the whole token space, unlike with session id's.) So, maybe 64 bits is enough.
2 ^ 63 / (100,000 * 60 * 60 * 24 * 365) = 2.93 * 10 ^ 6
-
tdlr: 32 is the magic number :) Thank you for looking into this. Commented May 5, 2015 at 0:46
-
1Well, 32 characters from the set [a-zA-Z0-9] should be fine, but 32 characters from the set [ab] is definitely insufficient. Probably better is to measure your "minimum safe" threshold in terms of the number of bits of entropy inherent in the token generation process rather than the number of characters in the resulting string. Commented May 7, 2015 at 15:11
In CSRF an attacker can make many guesses. What if an employee visits an attackers site and then goes on Christmas vacation? An attacker could make many millions of cross-site requests. We have a similar concern for session id's. If either value is obtained then session is compromised. The same standards of strength should be applied to both CSRF tokens and Session IDs.
In both cases make sure the value expires. Can the attacker can't make 2^128 requests in a week, but eventually he will be able to. If your random number generator is weak, then you may think you have a 2^128th cryptographic nonce, but it might be much less.