5 ms·
> In other words, CSRF protection is about write protection, preventing unauthorized cross-origin actions, while CORS is about read protection, controlling who
by chuckadams 2y ago
> 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.
- PantaloonFlames 2y ago> 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/Access-Control-Allow-Origin#syntax https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Ac...
- chuckadams 2y agoYah 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.
- LudwigNagasena 2y agoAlso, nothing prevents you from checking the host server-side according to arbitrary logic and putting it into the CORS header dynamically.
- Retr0id 2y agoNothing prevents this, but the client must still emit preflight checks (an extra round-trip) for every endpoint, and again if headers need to change.
- dopp0 2y agoI think what he meant is that the wildcard is not supported in the origin itself, for instance: https://*.somedomain.com https://*.somedomain.com. per documentation, it's either "*" or "https://subdomain.somedomain.com https://subdomain.somedomain.com"
- chuckadams 2y agoThat 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.
- jcmfernandes 2y ago> 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.
- chuckadams 2y agoAh 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 ;)
- jcmfernandes 2y agoThat is correct :)
- catlifeonmars 2y ago> The RP must protect against CSRF when receiving the authorization code Is this via PKCE or (ID) token nonce validation?
- chuckadams 2y agoA nonce, kept in an extra query parameter named "state". https://stackoverflow.com/a/77029859 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)
- motorest 2y ago> 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.
- limbero 2y ago> 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)