22

I was just going through the OWASP's Cheat Sheet for CSRF Prevention. Regarding the double submit cookies method, it says:

the site should generate a (cryptographically strong) pseudorandom value

This method completely relies on the fact that Cookie/Header can not be injected by the attacker.

An attacker cannot read any data sent from the server or modify cookie values, per the same-origin policy.

Then, why should the pseudo random value be cryptographically strong?

Anders
  • 64,406
  • 24
  • 178
  • 215
thefourtheye
  • 333
  • 2
  • 12

3 Answers3

19

Short answer: To prevent brute forcing the CSRF token.

Let's take a trivial example: let's say your token is a single digit, accepting values from 0 to 9.
Now sure, an attacker cannot read this value from the cookie or header, but she does not have to - she can just have the attack send 10 CSRF requests, one with each possible value. One of them will be correct.

Using a cryptographically strong random value will prevent this, and can prevent the attacker from trying to scale up this attack (by having the attack send e.g. 1000 requests instead of 10, or 10,000, or... )

AviD
  • 72,138
  • 22
  • 136
  • 218
  • Can't we just counter this, by increasing the number of bits? – thefourtheye Dec 18 '13 at 13:06
  • 5
    @thefourtheye: At issue is predictability. A cryptographically strong random value cannot be predicted (which is why it is cryptographically strong). Sure, you can generate a 64-bit number, but if the attacker can *predict* the numbers you generate (or can narrow down the possible numbers to a brute-forceable range) then the extra bits add no extra security. – Martijn Pieters Dec 18 '13 at 13:18
  • @MartijnPieters Yup. I agree that. But, increasing the number of bits will make the token difficult to predict, right? – thefourtheye Dec 18 '13 at 13:20
  • 4
    @thefourtheye: `1 << 63 + randrange(10)` is 64 bits, but just as easy to predict as the example in this answer. So no, it depends on how the bits are generated. If you do it *properly*, you have a cryptographically strong random number *anyway*. – Martijn Pieters Dec 18 '13 at 13:22
  • @MartijnPieters Okay. I get what you are saying now. How about using `/dev/urandom` to generate it, instead of cryptographic algorithms? – thefourtheye Dec 18 '13 at 13:23
  • 2
    @thefourtheye: Yes, see [Is a rand from /dev/urandom secure for a login key?](http://security.stackexchange.com/q/3936) – Martijn Pieters Dec 18 '13 at 13:25
  • @MartijnPieters yes, that is exactly the point, thanks for explaining it. – AviD Dec 18 '13 at 13:41
  • @thefourtheye using /dev/urandom is fantastic, since it IS based on cryptographic algorithms.... – AviD Dec 18 '13 at 13:42
  • @AviD I believe `/dev/random` uses `Yarrow` algorithm, do you happen to know what is used in `/dev/urandom`? – thefourtheye Dec 18 '13 at 13:44
  • I dont remember offhand, but in general it is an internal implementation detail. Don't really need to worry about that. – AviD Dec 18 '13 at 13:48
  • I think this answer is wrong. The attacker doesn't "send" the request; he tricks a user into sending it. How can you trick a user to send a thousand requests? Please see my answer below. – John Wu Dec 19 '13 at 01:59
  • @JohnWu Tricking a user into sending a thousand requests is trivial, but CSRF does not even require the attacker to trick anyone. That is a misunderstanding of how CSRF works. – AviD Dec 19 '13 at 08:32
  • @AviD - if the csrf cookie and csrf header are sent by client and compared server-side by backend, and in CSRF an attacker can't set custom-headers, does this answer still apply? how can an attacker brute force CSRF then? – zerohedge Oct 15 '19 at 09:07
3

Combining the best of both answers:

  1. The token length needs to be proportional to the number of victims and the number of requests per victim. If an attacker convinces X victims to navigate to his page (by way of spam or phishing attacks) and each such page attempts Y different tokens then you need to protect yourself against 2x*y attacks. For example, if your token length is 16 bits long, an attacker needs to send out 216 emails that attempt 1 token each, or 28 emails that attempt 28 tokens each. An attacker can test multiple tokens with a single click using Javascript or by embedding multiple malicious image links per page.

  2. You want to use a cryptographically-secure random number generator to prevent attackers from requesting multiple tokens themselves, then using the sequence they got to predict what tokens other users will get in the near future.

Gili
  • 2,149
  • 3
  • 23
  • 41
2

It doesn't

It just has to be pseudo random.

CSRF is not compatible with brute force attacks. Consider the attack vector:

  1. Malicious user crafts a special email or web page with HTML that posts to the site of interest
  2. User is logged on to the site of interest, and the session ID is passed passively (it's a cookie)
  3. User is tricked into clicking the link in the specially crafted email or web page
  4. Link "forges" the request. The link doesn't have to contain the session ID because it's in the cookie. And it doesn't have to pass the CSRF token found in the header (it's passed passively-- it's a cookie). But it does have to contain the CSRF token in the form post.

There is no way a hacker is going to trick anyone into clicking a link hundreds of times. Even if it's a script that sends a ton of requests on a single click (assuming the hacker has figure out how to do that-- browsers don't allow cross-domain AJAX requests, so we're probably talking about a page containing hundreds of clear GIFS or something else totally whacky), it's not going to be able to get through a whole lot of search space without timing out.

Also, there is no way for the attacker to determine if the attack worked for a particular value-- it's a "fire and forget" attack.

So the idea that the CSRF token can be brute forced is far fetched at best. The hacker would have to be personally logged on-- which is a different attack entirely.

The only reason you need any entropy at all really is because CSRF attacks tend to be delivered via spam. Let's say you're an idiot and your CSRF token only has 16 bits of entropy, and the hacker sent out 65,536 spam emails with the exact same token. 65536/2^16 = one of those attacks would actually succeed. Assuming 0% of the emails hit spam filters, 100% of the users opened them, and 100% of the users happened to be logged into your app at the moment they clicked the evil link.

Other than hoping to sucker in a ton of users, there's no way for a hacker to scale the attack large enough to call it a brute force attack with any significance to it.

John Wu
  • 9,101
  • 1
  • 28
  • 39
  • 5
    Actually, this is wrong, on several key points. Brute force IS possible, just not at the level to crack 32 (or even 16) bytes of entropy. And while browsers do not allow cross domain AJAX requests, they DO allow cross domain POST requests - aka submitting a form (which is easy to do silently in javascript). Alternatively, that "page containing hundreds of clear GIFS" (or rather 1x1 pixel, at the very bottom of the page far below the break) is not so "wacky", and in fact HAS been seen in the wild. So yeah, if the CSRF token space is small enough, or predictable enough, it CAN be brute forced. – AviD Dec 19 '13 at 08:31
  • 2
    That is why CRNG *is* required, to ensure that it is not predictable, as I explained in my answer. Remember, the CSRF attacker does NOT need to "trick" you into clicking a link, the CSRF requests can be sent out silently - either via POST requests in javascript or "hidden" IMG tags. – AviD Dec 19 '13 at 08:34
  • Yes it is "easy enough" to submit a form silently in Javascript-- but only one (see [here](http://stackoverflow.com/questions/1927618/is-to-possible-to-submit-two-forms-simultaneously)). Maybe two if you work really hard (see [here](http://yogendrakrsingh.blogspot.in/2010/03/javascript-trick-submitting-multiple.html)). It is impossible to submit 2^16 forms. More importantly, the hacker has absolutely no control over timing-- the user will open the page at his leisure. Arguing about 64 bits of entropy and/or "true" unpredictability is absurd when you understand the attack vector. – John Wu Dec 19 '13 at 15:13
  • 2
    Huh what? It is trivial to submit multiple standard POST requests via javascript. I don't understand the confusion in those links, and the SO question is not exactly the same thing you're referring to here. I agree that 2^16 bits of entropy would be too difficult to brute force in this way, but 10 / 100 / 2^8 is easily within realm of feasible. I am not sure what part of the attack vector you're misunderstanding. – AviD Dec 19 '13 at 15:25
  • Perhaps we agree then. In my answer above I state you'd have to be an idiot to use 16 bits (or less) of entropy. – John Wu Dec 19 '13 at 15:32
  • 2
    And I explicitly agreed, that with enough entropy it is resistant to brute force, and you don't even need 256 bits of entropy to get there. What we don't agree on, is that CSRF tokens with low entropy *can* be brute forced, and that CSRF attacks do not require "tricking" the victim. – AviD Dec 19 '13 at 15:38
  • The victim need not be tricked into clicking a link, but they need to be tricked into opening a web page or email containing malicious content. I also disagree with your language that implies the hacker can "send" CSRF requests; the naive user sends them via a "confused deputy" a.k.a. the user's browser. – John Wu Dec 19 '13 at 16:35
  • Of course I agree on the 2nd point, I clarified the one place it was ambiguous. No trickery is necessary, "opening a web page" is something people do all the time, like on forums... Reddit... Q&A sites... Sure, it's easier if you DO browse to my own site, under my full control, but still possible. – AviD Dec 19 '13 at 16:41
  • I'd rather argue about technical things (as opposed to arguing about language usage). OWASP uses the term "trick" as in "Cross-Site Request Forgery (CSRF) is an attack that tricks the victim into loading a page that contains a malicious request." therefore I stand by my criticism. – John Wu Dec 19 '13 at 16:48
  • A. I'll fix that real soon ;-) B. Even if you rely on initial trickery to get the victim to your page, there is still no basis to think that you need to *keep* tricking him for every request. Once he's on your page, you can have your way with him, and send as many requests as you like. – AviD Dec 19 '13 at 16:51
  • @JohnWu: Depends on the implementation of the victim site but there is certainly nothing stopping someone coding something that submits 1000's of POST requests on a page (e.g. via hidden IFrames). – SilverlightFox Dec 26 '13 at 13:30