pillarjs / understanding-csrf

What are CSRF tokens and how do they work?
1.4k stars 120 forks source link

Add origin header checking #13

Open g-k opened 7 years ago

g-k commented 7 years ago

It is more robust than referrer checking and a nice addition to tokens.

http://seclab.stanford.edu/websec/csrf/csrf.pdf (proposed here) https://wiki.mozilla.org/Security/Origin

tompazourek commented 6 years ago

If understand it correctly, an app that would use only server-side Origin header checking alone would prevent CSRF in all browsers that implement the Origin header correctly.

Clients with older browsers that don't send Origin headers then wouldn't be protected, and CSRF could still happen there.

In relation to CSRF protection, the most important bit is that the Origin header is sent with an ordinary form submitted as POST (IIRC Firefox used to have issues with that).

Does anyone know of some data about how well is the Origin header implemented in major browsers? Like from which version they send the Origin header, especially in normal POST submits.

This might be interesting to know, because it could help determine how viable it would be to use just Origin header checking for CSRF protection. If e.g. 95% of browsers out there send Origin header with ordinary POST form submits, we might not need any other protection and could be alright with the remaining 5% being susceptible to CSRF (they're probably older browsers with other security issues anyway).

Any detailed browser support data for this?

g-k commented 6 years ago

If understand it correctly, an app that would use only server-side Origin header checking alone would prevent CSRF in all browsers that implement the Origin header correctly.

Clients with older browsers that don't send Origin headers then wouldn't be protected, and CSRF could still happen there.

For lenient header checking (requests missing the headers are accepted or it "fails open"), yes.

Strict header checking over TLS should be fine if the site is OK breaking support for requests without the headers.

Tokens are still the most robust solution, but strict header checking can make sense for embedded or IoT applications.

Any detailed browser support data for this?

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin#Browser_compatibility says the current versions of all browsers but no POST requests from Firefox. I don't see version numbers in https://caniuse.com/

tompazourek commented 6 years ago

Thanks for getting back to me. Yeh, I've seen the data both on Can I Use and MDN, unfortunately, they're not very detailed regarding the version and specifics of the POST forms and Origin header.

I found a very good article on OWASP wiki (CSRF Prevention Cheat Sheet). TL;DR: They recommend to check both the Origin and Referer headers, and if they are both empty, then fail to process the request. On top of that, they still recommend using token validation (however they say it's possible to rely on just the header checking):

(...) we recommend a second check as an additional precaution to really make sure. This second check can involve custom defense mechanisms using CSRF specific tokens created and verified by your application or can rely on the presence of other HTTP headers depending on the level of rigor/security you want.

I've just tested Firefox (version 56), and unfortunately, it still has the issue with not sending Origin headers when POSTing forms... But at least it still sends the Referer header correctly.

But I've always considered the Referer header to be unreliable as I remember some antiviruses and firewalls used to remove the Referer header for privacy reasons. I'm not sure if they can do that if the site is running on HTTPS, and on POST requests, but I guess it might be possible to mess with the headers through some browser extension. I'm not really sure what the state of Referer header filtering is in 2017.

Although OWASP still consider the case where both Referer and Origin headers missing as very rare:

If neither of these headers is present, which should be VERY rare, you can either accept or block the request. We recommend blocking, particularly if you aren't using a random CSRF token as your second check.