ChatGPT解决这个技术问题 Extra ChatGPT

CSRF protection with CORS Origin header vs. CSRF token

This question is about protecting against Cross Site Request Forgery attacks only.

It is specifically about: Is protection via the Origin header (CORS) as good as the protection via a CSRF token?

Example:

Alice is logged in (using a cookie) with her browser to https://example.com. I assume, that she uses a modern browser.

Alice visits https://evil.example, and evil.example's client side code performs some kind of request to https://example.com (classic CSRF scenario).

So:

If we don't check the Origin header (server-side), and no CSRF token, we have a CSRF security hole.

If we check a CSRF token, we're safe (but it's a bit tedious).

If we do check the Origin header, the request from evil.example's client side code should be blocked just as well as it would when using a CSRF token - except, if it is possible somehow for evil.example's code to set the Origin header.

I know, that this should not be possible with XHR (see e.g. Security for cross-origin resource sharing), at least not, if we trust the W3C spec to be implemented correctly in all modern browsers (can we?)

But what about other kinds of requests - e.g. form submit? Loading a script/img/... tag? Or any other way a page can use to (legally) create a request? Or maybe some known JS hack?

Note: I am not talking about

native applications,

manipulated browsers,

cross site scripting bugs in example.com's page,

...

I believe many proxies strip the origin header.
And for form submit and img/script tags, we should rely on CSPs, not sure about the old browsers though.
@thefourtheye: Since the connection is initiated over TLS the user has a far more pressing issue than CSRF if a proxy can man-in-the-middle him/her.
@thefourtheye, why would they strip Origin? That would negate CORS protection.
I like this question and its answers because they are about something specific, but they also remind me of the difference between CSRF and CORS. (I admit those are not easily confusable concepts... But I still manage to confuse them.)

C
Community

know, that this should not be possible with XHR (see e.g. Security for cross-origin resource sharing), at least not, if we trust the W3C spec to be implemented correctly in all modern browsers (can we?)

At the end of the day you have to "trust" the client browser to safely store user's data and protect the client-side of the session. If you don't trust the client browser, then you should stop using the web at all for anything other than static content. Even with using CSRF tokens, you are trusting the client browser to correctly obey the Same Origin Policy.

While there have been previous browser vulnerabilities such as those in IE 5.5/6.0 where it has been possible for attackers to bypass the Same Origin Policy and execute attacks, you can typically expect these to be patched as soon as discovered and with most browsers automatically updating, this risk will be mostly mitigated.

But what about other kinds of requests - e.g. form submit? Loading a script/img/... tag? Or any other way a page can use to (legally) create a request? Or maybe some known JS hack?

The Origin header is normally only sent for XHR cross-domain requests. Image requests do not contain the header.

Note: I am not talking about native applications, manipulated browsers, cross site scripting bugs in example.com's page,

I'm not sure whether this falls under manipulated browsers or not, but old versions of Flash allowed arbitrary headers to be set which would enable an attacker to send a request with a spoofed referer header from the victim's machine in order to execute an attack.


The Flash example is a good one - and maybe other plugins may have a similar vulnerability. I can (unfortunately) only protect Alice from CSRF, if she uses a modern browser etc, that's clear. But it is not unreasonable, that even as a security-aware user, she might have installed 3rd party plugins - especially when they are from large (trustworthy) companies. Even though they may write safe plugins, I'm not 100% convinced, if they also think about CSRF! So unless browser sandboxes restrict the plugins from violating SOP (do they maybe?), I'd rather recommend to stick with the CSRF token.
@ChrisLercher: Yes modern day plugins appear to be a bit more robust. However, at any moment a new version could be released that allows an attacker to leverage it in such a way to bypass browser protections. The best way to handle it (e.g. token/header) will depend on the sensitivity of your data and whether such a risk is acceptable. Flash does obey a SOP, but the origin of a Flash plugin is the site it was loaded from (rather than the calling site like JavaScript). There is a crossdomain.xml that can enable cross-domain communication.
If the origin header is missing, a server can always reject the request, which mitigates the img src attribute type of attack. But agree, the trustless approach would encourage a csrf token.
g
guest

Web content can't tamper with the Origin header. Furthermore, under the same origin policy, one origin can't even send custom headers to other origins. [1]

Thus, checking the Origin header is just as good at blocking attacks as using a CSRF token.

The main concern with relying on this is whether it it lets all legitimate requests work. The asker knows about this issue, and has set up the question to rule out the major cases (no old browsers, HTTPS only).

Browser vendors follow these rules, but what about plugins? They might not, but the question disregards "manipulated browsers." What about bugs in the browser that let an attacker forge the Origin header? There can be bugs that allow the CSRF token to leak across origins too, so it would take more work to argue that one is better than the other.


I've just tested Firefox 47 and it does not send an origin header for a cross-origin form post (a common way of attacking REST services that don't enable CORS for XHR), so I don't think an origin header check would be effective if the user is using Firefox.
For reference, the issue of Firefox not sending an "Origin" header is tracked at Bugzilla: bugzilla.mozilla.org/show_bug.cgi?id=446344 You could fallback to checking the "Referer" header in this case but in my experience some Firefox users block the "Referer" header because of privacy concerns (although IMHO it would be enough to strip the path and query).
A
Adam

Explaining the terms

I think the question should be same-origin policy vs CSRF token. Because CORS is a mechanism to allow two different domains to talk to each other (by relaxing same-origin policy), whereas same-origin policy and CSRF token restrict domains to talk to each other.

GET methods are never save

All browsers implement the same-origin policy. This policy avoids in general that a web application on domain A can make a HTTP request to an application on domain B. However, it does not restrict all requests. For example same-origin policy does not restrict embed tags like this:

<img src="https://dashboard.example.com/post-message/hello">

It’s irrelevant whether the response is a valid image — the request is still executed. This is why it’s important that state-changing endpoints on your web application cannot be invoked with the GET method.

Preflight check

You may use CORS to avoid same-origin policy and let the domain A make a request to domain B that would otherwise be forbidden. Before the actually request is send, a preflight request will be send to check if the server allows domain A to send this request type. If it does, domain A will send the original request.

For example, if no CORS are set, then a Javascript XMLHttpRequests would be restricted for domain A by a preflight, without executing the request on domain B.

Why you need CSRF token despite same-origin policy

If same-origin policy would work for all types of request then you would be right and there is no need to use CSRF token, because you would have full protection by the same-origin policy. However, this is not the case. There are a couple of HTTP requests that do not send a preflight request!

GET, HEAD and POST requests with specific headers and specific content-type do not send a preflight request. Such requests are called simple requests. This means the request will be executed and if the request was not allowed, then a not-allowed error response will be returned. But the problem is, that the simple request was executed on the server.

Unfortunately, a plain <form action="POST"> creates a simple requests!

And because of these simple requests, we have to protect the POST routes with CSRF tokens (GET routes don't need CSRF because they can be read anyway by embedded tags as shown above. Just make sure you don't have a state-changing get method).


Quote "...simple requests,... the request will be executed and if the request was not allowed, then a not-allowed error response will be returned." So you are saying the server will reject the request? Then why is CSRF token still necessary here?
@Morris server will execute and return an error message. So it will upda profile or w/e and respond with no access
What's preventing a evil domain from first scraping the HTML form string, obtaining token, then submitting evil requests with token? I've seen in above discussions, some said "Form HTML must require authentication", but we also said "When myApp is logged in, Evil domain can make a request to myApp domain, and browser will automatically send myApp cookies" - doesn't it mean Evil domain's request would still be considered "authenticated" ?
@Morris CSRF token is matched vs a key stored in a session. If you obtain token but wihtout the cookie of the user, meaning without session, then request is not executed and you get error message.
I don't get it: if the server checks the value of the Origin header and rejects requests with invalid origin, why do I still need CSRF token?