News for hackers. Stuff that matters.
Re:Why do we have both CSRF protection and CORS? by beala on Sunday March 02, 2025 @05:23PM (#43235882)
If I may attempt to summarize:

CORS is a mechanism for servers to explicitly tell browsers which cross-origin requests can read responses. By default, browsers block cross-origin scripts from reading responses. Unless explicitly permitted, the response cannot be read by the requesting domain.

For example, a script on evil.com might send a request to bank.com/transactions to try and read the victim's transaction history. The browser allows the request to reach bank.com, but blocks evil.com from reading the response.

CSRF protection prevents malicious cross-origin requests from performing unauthorized actions on behalf of an authenticated user. If a script on evil.com sends a request to perform actions on bank.com (e.g., transferring money by requesting bank.com/transfer?from=victim&to=hacker), the server-side CSRF protection at bank.com rejects it (likely because the request because it doesn’t contains a secret CSRF token).

In other words, CSRF protection is about write protection, preventing unauthorized cross-origin actions, while CORS is about read protection, controlling who can read cross-origin responses.

Re:Why do we have both CSRF protection and CORS? by chuckadams on Sunday March 02, 2025 @06:21PM (#43236367)
> In other words, CSRF protection is about write protection, preventing unauthorized cross-origin actions, while CORS is about read protection, controlling who can read cross-origin responses.

I apologize for the length of the reply, I didn't have time to write a short one. But to sum up, CSRF is about writes, while CORS protects both reads and writes, and they're two very different things.

CSRF is a sort of "vulnerability", but really just a fact of the open web: that any site can create a form that POSTs any data to any other site. If you're on forum.evil.com and click the "reply" button (or anything at all), that could instead POST a transfer request to your.bank.com, and if you happen to be logged in, it'll happen with your currently authenticated session. When the bank implements CSRF protection, it ensures that a known token on the page (sometimes communicated through headers instead) is sent with the transfer. If that token isn't present, or doesn't match what's expected, reject the request. It ensures that only forms generated by bank.com will have any effect, and it works because evil.com can't use JS to read the content of the page from bank.com due to cross-origin restrictions.

CORS on the other hand is an escape hatch from a different cross-origin security mechanism that browsers enable by default: that a script on foo.com cannot make requests to bar.com except for "simple" requests (the definition of which is anything but simple; just assume any request that can do anything interesting is blocked). CORS is a way for bar.com to declare with a header that foo.com is in fact allowed to make such requests, and to drop the normal cross-origin blocking that would occur otherwise. You only have to use CORS to remove restrictions: if you do nothing, maximum security is the default. It's also strictly a browser technology: non-browser user agents do not need or use CORS and can call any API anytime.

Fun fact: you don't need CSRF protection at all if your API is strictly JSON-based, or uses any content type that isn't one of the built-in form enclosure types. The Powers That Be are talking about adding a json enclosure type to forms, but submitting it would be subject to cross-origin restrictions, same as it is with JS.

Re:Why do we have both CSRF protection and CORS? by jcmfernandes on Sunday March 02, 2025 @06:53PM (#43236645)
> Fun fact: you don't need CSRF protection at all if your API is strictly JSON-based, or uses any content type that isn't one of the built-in form enclosure types. The Powers That Be are talking about adding a json enclosure type to forms, but submitting it would be subject to cross-origin restrictions, same as it is with JS.

AFAIK, this is not totally accurate because the internet is a messy place. For example, the OAuth authorization code grant flow blesses passing the authorization code to the relying party (RP) in a GET request as a query parameter. The RP must protect against CSRF when receiving the authorization code.

Re:Why do we have both CSRF protection and CORS? by chuckadams on Sunday March 02, 2025 @07:01PM (#43236698)
Ah yes, good catch. That's what the `state` parameter is about, right? But I'll weasel out and say that lack of a content type (being a GET) is one of the built-in types too ;)
Re:Why do we have both CSRF protection and CORS? by jcmfernandes on Monday March 03, 2025 @04:04AM (#43239832)
That is correct :)
Re:Why do we have both CSRF protection and CORS? by catlifeonmars on Sunday March 02, 2025 @11:35PM (#43238339)
> The RP must protect against CSRF when receiving the authorization code

Is this via PKCE or (ID) token nonce validation?

Re:Why do we have both CSRF protection and CORS? by chuckadams on Monday March 03, 2025 @08:20AM (#43241451)
A nonce, kept in an extra query parameter named "state". https://stackoverflow.com/a/77029859 has some of the gory details (myself, I just hash the session's CSRF token to generate a state token)
Re:Why do we have both CSRF protection and CORS? by PantaloonFlames on Sunday March 02, 2025 @06:26PM (#43236411)
> It's a nice way to make an API "public", or would be if CORS supported a goddam wildcard for the host.

I don't get what you mean. Access-Control-Allow-Origin supports a wildcard. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Ac...

Re:Why do we have both CSRF protection and CORS? by LudwigNagasena on Sunday March 02, 2025 @07:21PM (#43236842)
Also, nothing prevents you from checking the host server-side according to arbitrary logic and putting it into the CORS header dynamically.
Re:Why do we have both CSRF protection and CORS? by Retr0id on Monday March 03, 2025 @07:37AM (#43241166)
Nothing prevents this, but the client must still emit preflight checks (an extra round-trip) for every endpoint, and again if headers need to change.
Re:Why do we have both CSRF protection and CORS? by chuckadams on Sunday March 02, 2025 @06:29PM (#43236436)
Yah you saw that before I edited it out, I realized that gripe was actually about the behavior of AWS API Gateway rather than CORS itself. It hates the wildcard, or something, I can't even remember exactly what the issue was. Thus did I zap it.
Re:Why do we have both CSRF protection and CORS? by dopp0 on Monday March 03, 2025 @06:44AM (#43240811)
I think what he meant is that the wildcard is not supported in the origin itself, for instance: https://*.somedomain.com.

per documentation, it's either "*" or "https://subdomain.somedomain.com"

Re:Why do we have both CSRF protection and CORS? by chuckadams on Monday March 03, 2025 @08:17AM (#43241432)
That was in fact it, lack of a subdomain wildcard. I got really confused because I opened one project I thought had this issue, saw the ACAO header was set to *, and thought I hallucinated the whole thing out of some different issue. But it was a different project where I needed to allow internal access, which would have been easy with a hardwired response with a wildcard, but instead I needed to write a whole lambda endpoint just to pull out the requesting host and put it in the ACAO header. Also easy, but what a waste.

Either way, kind of a digression into details of CORS that wasn't necessary for the introductory treatment, so I edited it out.

Re:Why do we have both CSRF protection and CORS? by motorest on Monday March 03, 2025 @02:30AM (#43239181)
> If you're on forum.evil.com and click the "reply" button (or anything at all), that could instead POST a transfer request to your.bank.com, and if you happen to be logged in, it'll happen with your currently authenticated session.

It should be clarified that by "currently authenticated session" it actually means cookies, which browsers are designed to automatically include in requests when they send a request to the same origin domain.

That's why CSRF attacks work: the attacker tricks the users' browser to send a request to a domain where the user was already authenticated, and that automatically inserts the user's session info in the request thus authorizing the request.

CSRF tokens work by adding a kind of API key that the browser somehow loads in a way that it is not stored as cookies. Servers then check for the CSRF token in each request to determine if the request is authorized. CSRF attacks alone don't work because they just forward cookies, and they do not include the CSRF token thus are rejected.

Re:Why do we have both CSRF protection and CORS? by limbero on Monday March 03, 2025 @10:26AM (#43242626)
> You only have to use CORS to remove restrictions: if you do nothing, maximum security is the default.

This is only true if you see CORS as a tool only to prevent reading data. I personally find it to be a useful tool to prevent writes, because the Origin header fulfils several of the purposes of a CSRF token. But that requires work on the backend to not actually perform writes unless the CORS parameters are valid. That sort of security is not the default (which is probably good)

Re:Why do we have both CSRF protection and CORS? by layer8 on Sunday March 02, 2025 @06:10PM (#43236283)
To add to that:

CORS is implemented by browsers based on standardized HTTP headers. It’s a web-standard browser-level mechanism.

CSRF protection is implemented server-side (plus parts of the client-side code) based on tokens and/or custom headers. It’s an application-specific mechanism that the browser is agnostic about.

Re:Why do we have both CSRF protection and CORS? by femto113 on Sunday March 02, 2025 @07:08PM (#43236749)
Some additional color:

CORS today is just an annoying artifact of a poorly conceived idea about domain names somehow being a meaningful security boundary. It never amounted to anything more than a server asking the client not to do something with no mechanism to force the client to comply and no direct way for the server to tell if the client is complying. It has never offered any security value, workarounds were developed before it even became a settled standard. It's so much more likely to prevent legitimate use than protect against illegitimate use that browsers typically include a way to turn it off.

With CSRF the idea is that the server wants to be able verify that a request from a client is one it invited (most commonly that a POST comes from a form that it served in an earlier GET). It's entirely up to the server to design the mechanism for that, the client typically has no idea its happening (it's just feeding back to the server on a later request something it got from the server on a previous request). Also notable is despite the "cross-site" part of the name it doesn't really have any direct relationship to "sites" or domains, servers can and do use the exact same mechanisms to detect or prevent issues like accidentally submitting the same form twice.

Re:Why do we have both CSRF protection and CORS? by robocat on Monday March 03, 2025 @02:16AM (#43239115)
> domain names somehow being a meaningful security boundary

That's your Internet opinion. Perhaps expand on why you think that?

I reckon domains have quite a few strong security features. Strong enough that we use them to help access valuable accounts

Re:Why do we have both CSRF protection and CORS? by tsimionescu on Monday March 03, 2025 @06:31AM (#43240721)
CSRF wouldn't work as easily if CORS (or, more precisely, the single origin policy that CORS allows you to circumvent in controlled ways) weren't there. And both cookies and TLS also rely entirely on domains being a meaningful security boundary.

Without the SOP, evil.com could simply use JS to read the pages from bank.com, get a valid CSRF token, and then ask the browser to send a request to bank.com using its own CSRF token and the user's cookie. This maybe could be circumvented by tying the cookie and the original CSRF token together, but there might be other ways around that. Plus, if the browser wasn't enforcing the SOP, then the different tabs might just be able to read each other's variables, since that is a feature today for multiple tabs accessing the same origin.

Re:Why do we have both CSRF protection and CORS? by smagin on Monday March 03, 2025 @07:00AM (#43240922)
well it does make sense to assume that by default different origins belong to different people, and some of those people don't have to behave friendly to each other.

There is little server can do with that, because of the request-based model. The state that persists between requests lives in cookies, and it's browser job not to expose those cookies all around. Turning off single origin policy would be a terrible idea. For one, it makes CSRF work by not allowing cross-origin reads.

Re:Why do we have both CSRF protection and CORS? by dasil003 on Monday March 03, 2025 @09:43AM (#43242206)
I’m not sure in what world domains aren’t a meaningful security boundary, but cross-origin prevention is absolutely necessary in a world with private web apps and scriptable browsers.

Maybe you are of the opinion that the web should have stayed document only and apps should have stayed native binaries, but as far as the web is concerned the default cross-origin request policy is a critical security pillar.

Re:Why do we have both CSRF protection and CORS? by alexashka on Sunday March 02, 2025 @06:15PM (#43236320)
Regarding CSRF - how would I be authenticated to do actions on bank.com when I'm on evil.com?

It seems like the problem is at the level of login information somehow crossing domain boundaries?

What stops a script on evil.com from going to bank.com to get a CSRF token and then including that in their evil request?

Re:Why do we have both CSRF protection and CORS? by chuckadams on Sunday March 02, 2025 @07:10PM (#43236762)
> It seems like the problem is at the level of login information somehow crossing domain boundaries?

The login information isn't so much crossing boundaries -- evil.com can't read your session cookie on bank.com -- but cookies that don't set a SameSite attribute allow anyone to send that information on your behalf, and effectively act as you in that request. Textbook example of a "confused deputy" attack.

> What stops a script on evil.com from going to bank.com to get a CSRF token and then including that in their evil request?

The token is either stored on the page that bank.com sends (for a html form) or was sent in a header and stored in local storage (for API clients). In neither case can evil.com read that information, due to cross-origin restrictions, and it changes with every form.

Re:Why do we have both CSRF protection and CORS? by alexashka on Sunday March 02, 2025 @07:41PM (#43237019)
> In neither case can evil.com read that information

What stops evil.com from having an API endpoint called evil.com/returnBankCSRFToken that goes to bank.com, scrapes token and returns it?

CSRF tokens are just part of an html form - they are not hidden or obscured and thus scraping them is trivial.

When I go to evil.com, it calls the endpoint, gets token and sends a request to bank.com using said token, thus bypassing CSRF?

Re:Why do we have both CSRF protection and CORS? by hkpack on Sunday March 02, 2025 @07:52PM (#43237111)
Nothing stops, but it will be a different CSRF token, which will not match to the one generated for the original page.

Server keeps track of which CSRF token is given to which client using cookies (usually some form of SessionID), and stores it on the server somewhere.

It is a very common pattern and all frameworks support it with the concept of "sessions" on the back end.

Re:Why do we have both CSRF protection and CORS? by hansonkd on Sunday March 02, 2025 @08:36PM (#43237384)
> stores it on the server somewhere

you don't need to store anything on the server. cookies for that domain are sent with the request and it is enough for the server to check its cookie with the csrf request data.

browsers would send the bank.com cookies with the bank.com request. It is security built into the browser which is why its so important to use secure browsers and secure cookies.

If the malicious user convinces the user to use an insecure browser you can circumvent CSRF, but at that point there are probably other exploits you can do.

Re:Why do we have both CSRF protection and CORS? by mewpmewp2 on Monday March 03, 2025 @10:27AM (#43242644)
How does server know the cookie is valid if it doesn't store it and how does it know csrf token is valid if it doesn't store it and finally how does it know that this csrf token relates to this cookie session token if it doesn't store it?
Re:Why do we have both CSRF protection and CORS? by hansonkd on Monday March 03, 2025 @12:48PM (#43244547)
The CSRF token can have nothing to do with the cookie session information. you can store CSRF as a separate cookie.

You can validate the CSRF is valid by keeping a key on your server and matching that the token you get can be derived from that key.

See Django's implementation of CSRF for more details. CSRF tokens are separate from session and no CSRF information needs to be stored in database to validate CSRF.

Re:Why do we have both CSRF protection and CORS? by smagin on Monday March 03, 2025 @10:37AM (#43242750)
> How does server know the cookie is valid if it doesn't store it

depending on why you'are asking the question, * because it decrypts correctly * because it contains some user identifier

People don't usually store sessions in cookies because cookies can't be very big, and session do become big. So what people do instead they store cookies in databases, and put session identifiers into cookies.

Re:Why do we have both CSRF protection and CORS? by hansonkd on Monday March 03, 2025 @12:47PM (#43244524)
You don't need to store CSRF in sessions. Django doesn't by default.

CSRF token can be entirely separate from sessions.

Re:Why do we have both CSRF protection and CORS? by smagin on Monday March 03, 2025 @01:47PM (#43245253)
not even you don't need to, you shouldn't. Sessions shouldn't be accessible to js at all
Re:Why do we have both CSRF protection and CORS? by chii on Monday March 03, 2025 @02:50AM (#43239298)
> What stops evil.com from having an API endpoint called evil.com/returnBankCSRFToken that goes to bank.com, scrapes token and returns it?

so evil.com will now require some sort of authentication mechanism with bank.com to scrape a valid CSRF token. If this authentication works (either if the user willingly gave their login information to evil.com, or they have a deal with bank.com directly), then there's no issues, and it works as expected.

Re:Why do we have both CSRF protection and CORS? by hombre_fatal on Tuesday March 04, 2025 @03:26PM (#43259483)
The key is that CSRF is protecting against the browser's automatic behavior of sending cookies along with cross-origin requests.

A form on evil.com posted to bank.com does send your cookies by default.

But not for fetch() in the browser. And certainly not for a request made from evil.com's server.

Also, bank.com would want to create CSRF tokens tied to current user. Or ensure its CORS protections never allow cross-origin requests (the default) if it were to use generic CSRF tokens.

Or just use same-origin cookies.

Or don't even use cookies at all.

Re:Why do we have both CSRF protection and CORS? by gavinsyancey on Sunday March 02, 2025 @06:24PM (#43236384)
When you logged in to bank.com, it set a cookie that your browser presents when it makes any request to bank.com, regardless of how it was initiated (i.e. it would still send the cookie on a cross-site XHR initiated by evil.com's JavaScript).

> What stops a script on evil.com from going to bank.com...

CORS

Re:Why do we have both CSRF protection and CORS? by Macha on Sunday March 02, 2025 @07:14PM (#43236787)
Note that cookies now have the SameSite cookie option which should prevent this
Re:Why do we have both CSRF protection and CORS? by alexashka on Sunday March 02, 2025 @06:32PM (#43236458)
> it set a cookie that your browser presents when it makes any request to bank.com, regardless of how it was initiated

Right, this seems like a very bad idea and now everyone has to do CSRF because of it?

CORS doesn't prevent evil.com from sending a reqeust to bank.com, it only prevents reading the response, no?

So again, what stops evil.com from sending a request to say transfer 1 BBBBillion dollars to bank.com and including a CSRF token it gets from visiting bank.com?

Re:Why do we have both CSRF protection and CORS? by chuckadams on Sunday March 02, 2025 @07:21PM (#43236839)
> Right, this seems like a very bad idea and now everyone has to do CSRF because of it?

Yep, that pretty much sums it up.

CORS doesn't have to enter into it though: evil.com just has no way to read the CSRF token from bank.com, it's a one-time password that changes with every form (one hopes) and it's embedded in places that it can't access. It can send an arbitrary POST request, but no script originating from evil.com (or anywhere that is not bank.com) can get at the token it would need for that post to get past the CSRF prevention layer.

Re:Why do we have both CSRF protection and CORS? by voxic11 on Sunday March 02, 2025 @06:47PM (#43236579)
> it only prevents reading the response, no?

> So again, what stops evil.com from sending a request to say transfer 1 BBBBillion dollars to bank.com and including a CSRF token it gets from visiting bank.com?

It can't read the response from bank.com so it can't read the CSRF token. The token is basically proving the caller is allowed to read bank.com with the user's credentials. Which is only possible if the caller lives on bank.com or a origin that bank.com has allowed via CORS.

Re:Why do we have both CSRF protection and CORS? by blincoln on Monday March 03, 2025 @07:23AM (#43241081)
CSRF tokens are only valid for a particular user, or session, or sometimes even a particular page load.

If there's a way for evil.com to obtain a CSRF token that's valid for an arbitrary user, it's a vulnerability, just like if evil.com could obtain the user's session token, JWT, etc.

Re:Why do we have both CSRF protection and CORS? by JimDabell on Monday March 03, 2025 @12:13AM (#43238513)
> > What stops a script on evil.com from going to bank.com...

> CORS

CORS does the exact opposite to what you think.

Those types of cross-site requests are forbidden by default by the Same-Origin Policy (SOP) and CORS is designed so you can allow those requests where they would otherwise be forbidden.

CORS is not a security barrier. Adding CORS removes a security barrier.

Re:Why do we have both CSRF protection and CORS? by Sohcahtoa82 on Monday March 03, 2025 @05:08PM (#43247443)
> > What stops a script on evil.com from going to bank.com...

> CORS

Incorrect. It's SOP that prevents an evil.com script from going to bank.com

It's CORS that allows evil.com. CORS is an insecurity feature that relaxes the SOP.