5

CSRF tokens are used a lot.

The server sets a token in cookie for that domain that either (1) include in the HTML form or (2) Javascript can read and include in the request. The server verifies the token in the request matches the token in the cookie.


But why not simply check the Origin header? According to OWASP, that's why it exists:

The Origin HTTP Header standard was introduced as a method of defending against CSRF and other Cross-Domain attacks.

"Is the Origin not there? If not, OK. If it is, is it one one I trust (e.g. the same origin)? If so, OK."


CSRF tokens can be troublesome. They are

  • more difficult for beginners to understand -- "Wait...I send it twice? What's CRSF again?"
  • requires cookies (granted, not usually a problem)
  • more difficult to implement -- needs controller and view
  • less flexible -- can't ever work cross-domain
  • strange in non-web settings -- "Why does your API need a CSRF token?" "Oh, 'cause JS uses that too."
  • more cumbersome to implement globally -- "Oops, forgot the CSRF tag here among my 25 HTML form fields"

Given these disadvantages, why are CSRF tokens so commonly used, rather than the Origin header?

Paul Draper
  • 958
  • 8
  • 18
  • 1
    http://stackoverflow.com/questions/24680302/csrf-protection-with-cors-origin-header-vs-csrf-token Here is a similar question. – sir_k Dec 08 '14 at 09:15
  • CSRF tokens are the best method to prevent CSRF vulnerabilities. There are other checks that help with prevention like the origin header, different types of challenges, and checking the referrer header. While these methods can help with prevention, none of them are as effective as tokens. – Paraplastic2 Dec 08 '14 at 13:56

2 Answers2

6

You can't currently depend on the Origin header, because it is not implemented in all browsers which are in active use. Apart from that, Origin is not sent in all cases relevant to CSRF, like

<img src=http://router/admin.cgi?...>
Steffen Ullrich
  • 184,332
  • 29
  • 363
  • 424
  • @PaulDraper: just tested with latest Chrome and Firefox. Both don't sent an Origin header if including an image from a remote site. But this is a typical vector for CSRF. – Steffen Ullrich Dec 08 '14 at 13:34
  • Hm....it would seem inappropriate then for OWASP to recommend it, right? "This section details other ways that an application can prevent CSRF by relying upon similar rules that *CSRF exploits can never break*...Checking The Origin Header". – Paul Draper Dec 08 '14 at 14:04
  • 2
    @PaulDraper: it does not say that you can rely on the Origin header to exist, only "If the origin header is present, then it should be checked for consistency." – Steffen Ullrich Dec 08 '14 at 14:08
  • 1
    @PaulDraper Strictly speaking, I think if you treat a lack of origin as a failed origin-match, a CSRF attack can't break your *security*, but your website may still break (i.e., *fail to function normally* for browsers that never send `Origin` headers) without an attack. An attack doesn't break your site; the browser's failure to send an `Origin` header breaks your site. That's obviously not great site design, but that's only reading of "rules that CSRF exploits can never break" I can think of that is strictly correct. – apsillers Dec 08 '14 at 14:08
  • @apsillers: yes, you can be sure that no sane browser will allow you to fake an Origin header in cross-origin requests, but you cannot be sure that the browser will send an Origin header at all. – Steffen Ullrich Dec 08 '14 at 14:11
  • 2
    Since `GET` is a safe operation (as defined the HTTP standard), I suppose checking the Origin header would be sufficient for preventing non-safe operations from any modern browser to a standards-compliant server. That is sufficient in my case. – Paul Draper Jan 30 '15 at 01:08
  • [OWASP](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Disclosure_of_Token_in_URL): "The ideal solution is to only include the CSRF token in POST requests and modify server-side actions that have state changing affect to only respond to POST requests. This is in fact what the RFC 2616 requires for GET requests. If sensitive server-side actions are guaranteed to only ever respond to POST requests, then there is no need to include the token in GET requests." – Paul Draper Jul 29 '15 at 14:41
0

"Is the Origin not there? If not, OK. If it is, is it one one I trust (e.g. the same origin)? If so, OK."

Although you can use the Origin header to reject a request. If the Origin header is missing, you cannot safely accept it, even for POST requests. As far as I know, an HTML form request doesn't include an Origin header, and neither do imgs, scripts, links, cos background images, or other places that make get requests. And of course the Origin header isn't sent for XHR requests on the same host, so you need another protection mechanism.

One option is to put the csrf token in a custom header, which is easier to do globally and doesn't put the token in the URL for get requests. And then if desired you can check that the request either has the Origin header or custom header.

You might also be able to do something like the method you mentioned, provided you reject any request that isn't an Ajax request. But I am not as confident about the security of that.

In short the Origin header, by itself isn't enough if you want to make same-origin requests, but could be used in combination with another csrf protection method.

Thayne
  • 101
  • 4
  • It would seem that for form POSTs, some browsers include the Origin header, but others do not. It does seem incongruous with OWASP: "This section details other ways that an application can prevent CSRF by relying upon similar rules that *CSRF exploits can never break.*" – Paul Draper Jul 29 '15 at 14:33
  • And if it is not present? – Paul Draper Jul 29 '15 at 14:40
  • "If the origin header is present, then it should be checked for consistency." OWASP doesn't say it is safe to accept requests without an Origin header, merely that if the header is present it can't be broken by CSRF. The section on using the referrer header states that if it is missing it must be rejected – Thayne Jul 29 '15 at 14:43
  • There is the potential for vulnerability if even one browser doesn't send the header. – Thayne Jul 29 '15 at 14:44
  • 1
    Yeah, it certainly does seem like a subpar recommendation. – Paul Draper Jul 29 '15 at 17:35