8 ms·
CORS Is Stupid
- _nhh 2y ago100% agree. CORS is very clunky
- Fethbita 2y agoEvery time I need to fiddle with CORS is CSP, I have to read the MDN pages for them, could never get them to stick intuitively. This is a nice article but more info on CORS would be nice.
- simonw 2y agoThis post doesn’t mention the other reasons the same origin policy was necessary: intranets. If your company hosts content on https://company-news.corp.internal/ https://company-news.corp.internal/ it’s very important that some random malicious site on the internet can’t use fetch() or XMLHttpRequest to read that page and exfiltrate that information, just from one of your employees being tricked into visiting that site. So it’s about more than just cookies.
- quohort 2y agoHmm, true. But perhaps you could mitigate this with cookies as OP suggests. Simply don't return anything unless the GET request has a valid intranet cookie? Or perhaps the client can tell the server what webpage it's fetching from and the security check can be done server-side? It is just strange to me that this security check has to be done on client-side (in the browser) as opposed to on the web server actually responsible for distributing the content.
- splix 2y agoYou definitely could. But I guess it should be secure by default. Even if you didn't implement any check on the server. Because people are lazy or they may forget to implement the security checks, or simply be unaware about them. Ex., when you hacked up a super simple script to display a number of today's users of your startup to display on the big screen in your office. You would probably want something as simple as possible. This page is just 3-5 lines of code. Maybe one-liner even. No authorization or other security, as it's for the office intranet. Without CORS any website that is visited by people from your office could fetch that number on screen.
- kevincox 2y agoEven with CORS, DNS rebinding may be a concern here. I think HTTPS may prevent that as the cert wouldn't contain the original site but in this setup where you want "no other security" it would probably work.
- marcosdumay 2y agoLAN segmentation is mostly stupid too. There is a case to make for old protocols and stuff Microsoft just won't fix (it's always Microsoft). But segmenting a web intranet because you expect the information not to escape is doubly stupid. It not only will escape through an infinity of exploits that exist everywhere; you have exactly 2 groups of people to make access control over, what it certainly insufficient; and finally, you constraint the capacity of people to work physically to inside your office.
- simonw 2y agoJust because it's stupid doesn't mean people haven't been doing it for more than twenty years.
- akira2501 2y ago> But segmenting a web intranet because you expect the information not to escape is doubly stupid. It's one layer in the security stack. It's not sufficient on it's own but there's no reason to get rid of it because it's not 100% effective. > you constraint the capacity of people to work physically to inside your office. Or, you know, just have a VPN.
- hn_throwaway_99 2y agoI didn't get this article. This first part explains common CSRF vulnerabilities, and then even explains the SameSite attribute, but it neglected to point out that SameSite=Lax is now the default on browsers, and has been for some time, specifically to mitigate the problems outlined in this article and to get rid of the need for CSRF tokens.
- kevincox 2y ago> SameSite=Lax is now the default on browsers Note on all major browsers unfortunately: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#browser_compatibility https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Se... A real shame, because it would be a pretty robust solution for sites that don't require any cross-origin interactions at all. That being said it is well supported if set explicitly. So if you can ensure that all cookies that your app sets have the attribute you should be good to go.
- debo_ 2y ago[flagged]
- simonw 2y agoOne of my favorite explanations of CORS is this one, which includes an interactive playground: https://jakearchibald.com/2021/cors/ https://jakearchibald.com/2021/cors/
- demarq 2y agoWait what The main premise of this post is false. The mentioned request can’t succeed without first completing a preflight check.
- garaetjjte 2y agoIt depends on content-type.
- demarq 2y agoI find it difficult to assume that’s what the author meant especially since they made no mention of content type. It doesn’t seem the author was aware of content type once you see their solution. Normally I would give the benefit of the doubt, but the “fix” is pretty damming here.
- davidfiala 2y agoIt depends on including things like headers and other non-approved changes to the request. Content-Type is one of them, but even it has some whitelisted options. Read about 'simple' requests to see what you can and cannot do before a preflight is required: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simpl...
- demarq 2y agoProbably you didn’t see my first reply. Put simply if I make cross origin POST request that’s JSON type it cannot be a simple request. There are no ways around this
- davidfiala 2y agoDidn't see it :) you nailed it!
- sweetjuly 2y ago> It provides both opt-out protections as an attempt to mitigate XSS attacks nitpick, I guess, but CORS is about CSRF (Cross Site Request Forgery) and not XSS (Cross Site Scripting). If you have an XSS bug, CORS can't save you since they can make requests from your origin.
- greenthrow 2y agoCORS is clunky. This article is not very good and I would not recommend just blindly following the advice given.
- le-mark 2y agoIt’s great when people learn things and write about it, that behavior enbiggens us all. But “X is stupid” screeds shows a lack of appreciation for historical context and why things are the way they are. No one had a grand design for the web and it is for better or worse a series of compromises.
- readthenotes1 2y agoReminds me of https://fs.blog/chestertons-fence/ https://fs.blog/chestertons-fence/
- alserio 2y agoWhile I do partly agree, as someone who is old, I don't expect the younglings to think we didn't do stupid things. We did because we did not know any better, because the world was new and fast and they seemed good at the time. Expecting the future to value the compromises we have chosen doesn't scale, piling complexity does not scale. I don't know how to solve this, but I doubt continuing to add complex and fragile hacks will work forever. In this sense "X is stupid".
- deleted 2y ago[deleted]
- LegionMammal978 2y agoMy biggest gripe with CORS is how the destination site needs to opt into it for requests of every kind. For instance, by default a cross-origin XMLHttpRequest or fetch() request will not include cookies, and if you ask it to include cookies, then the destination must include an Access-Control-Allow-Credentials header if you want the browser to allow it. So that's all well and good, except for the part where even requests without cookies still need an explicit Access-Control-Allow-Origin in the response. As far as I am aware, the only attack vector this protects against is when the destination decides to release sensitive information solely based on the IP address of the source, and not based on its cookies or any other information not already accessible to JS. (Obviously, the biggest instance of this is in the case of local network addresses, but there are efforts to further restrict cross-origin requests to such addresses, using a separate header, Access-Control-Allow-Private-Network [0].) I find this a shame, since it means that it's impossible to download most public data in a web app without proxying it through your own server, just because of this one edge case. [0] https://github.com/WICG/private-network-access https://github.com/WICG/private-network-access
- seri4l 2y ago>it means that it's impossible to download public data from a web app without proxying it through your own server. Maybe with a subdomain that points to the target website IP? If it supports HTTP and doesn't check the host header it should be fine. That's pretty exceptional these days though. Edit: I just checked and a subdomain won't do it, it needs CORS as well.
- esjeon 2y agoI was expecting a rant, but, wow, it was far better than that. This is a well founded criticism. CORS is an afterthought that never carefully integrated into the ecosystem, which resulted in bad DX. It’s so blunt that applying CORS always feels like a hack.
- davidfiala 2y agoIdeally TFA would have also explained why some requests do go through without a preflight. What's called a 'simple' request is the explanation behind TFA's whole premise. https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simpl... These days, pretty much everything requires a non-simple request in order to invoke an action, regardless of whether the client can read the result. Agree'd in spirit though that CORS is annoying to use, and it's always worth consulting the manual.
- kevincox 2y agoYeah, I had a section on this but decided to cut it because I felt the other protections mostly obsoleted the need to talk about this. > pretty much everything requires a non-simple request in order to invoke an action Except for POST request such as in forms. They may be a little out of fashion with JS-based frontends and JSON APIs but I would consider it a pretty gaping hole. If the list could be reduced to just HEAD and GET requests I would consider it a pretty complete protection. But POST seems like too big of a hole. (Although if you can block all requests that are POST with a "simple" Content-Type then you unlock a pretty robust protection.)
- alexpetros 2y agoLots of stuff about this article is strange: * The author first describes a mildly convoluted cookie-stripping middleware under "Actually Solving The Problem" and includes the much simpler `SameSite=Lax` cookie under "Defense in Depth" later on. * The author neglects to mention that `SameSite=Lax` is the default on all major browsers (still good to set it, though), which basically blows up the premise of the article, that all your cookies are one cross-origin form away from being mis-used * The author recommends _loosening_ the default CORS protections, which I guess makes sense if you think "CORS Is Stupid", but definitely makes your server less secure for basically no reason. The best way to deal with the Cross-Origin Resource Sharing restrictions is to simply set up your site so that it doesn't need to make cross-origin requests: serve your site from the same domain that it makes requests to, and make sure you set your cookies with `SameSite=Lax`, `Secure`, and `HttpOnly`. I outline this approach in more detail here: https://htmx.org/essays/web-security-basics-with-htmx/ https://htmx.org/essays/web-security-basics-with-htmx/ Also, while I still think that existing browser controls basically solve this problem, it's true that POST forms have some sneaky vulnerabilities due to backwards compatibility concerns. One way to help fix that is by introducing PUT, PATCH, and DELETE to HTML forms—methods which don't have the same CORS exceptions: https://alexanderpetros.com/triptych/form-http-methods https://alexanderpetros.com/triptych/form-http-methods
- noduerme 2y agoFTA: >> The default policy allows making requests, but you can’t read the results. This seems like the central premise of the article. Is the author just wrong about this? I'm confused. As I understand it, if the remote site sets Access-Control-Allow-Origin to a wildcard, and doesn't explicitly name the origin, then by default the browser will not send credentials with a request. Isn't that CORS working as intended? Was there some time in the past when browsers defaulted cookies to `SameSite=None`?
- kevincox 2y agoHow can the browser know not to send the credential before it gets the response that contains the Access-Control-Allow-Origin header? This is the crux of the issue. For many types of request (notably with `Content-Type: application/json`) the browser will send a preflight request. But there is a carve-out for "simple" requests which includes some POST requests. https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simpl... If you can be sure that you application doesn't do any writes on "simple requests" then your job gets a lot easier and you can mostly rely on `Access-Control-Allow-Origin: *` omitting credentials. But if you have endpoints that accept form-posts or don't check the request's Content-Type header than you need to be extra careful.
- porjo 2y agoI run into CORS issues often when fetching RSS feeds from browser Javascript [0], where the RSS provider has failed to currently set the Access-Control-Allow-Origin header [0] https://porjo.github.io/freshtube/ https://porjo.github.io/freshtube/
- kevincox 2y ago100%, this is one of the reasons that I want promote `Access-Control-Allow-Origin: *`. It allows client site RSS and link previews without needing a useless (and potentially privacy-harming) CORS proxy.
- jub0bs 2y agoYou cannot use `Access-Control-Allow-Origin: *` indiscriminately, though. In some cases, it can be dangerous: https://security.stackexchange.com/questions/227779/concrete-example-of-how-can-access-control-allow-origin-cause-security-risks https://security.stackexchange.com/questions/227779/concrete...
- kevincox 2y agoI agree with those points but I don't think they mean that we shouldn't be promoting that header as a common solution. > Server bound to an inaccessible network interface This is a niche use case. Most sites don't have this problem. > Distributed client-side brute-force attack against login This is pretty easy to solve by adding checks on your login endpoint. But really you should have more robust solutions against login rate limit whether or not they can be triggered by clients on different sites.
- Too 2y agoDo people use XSRF-tokens nowadays? That used to be the standard approach to this, before all browser CORS protection came to be. The server gives the client a token on the top level page, that must be included in any subsequent POST requests, while also requiring the cookies. Seems like a safer approach, unless you fully trust all browsers to get CORS correct. It's similar to the Authorization header technique, except you would normally submit it as a parameter in the POST request instead of headers. Explicit credentials are good but has some drawbacks, by being in the headers, you must submit it using fetch(), making it difficult to use in forms or <a>-tags, there the implicit credentials work smoother.
- h_tbob 2y agoAnytime who complains about CORS has my instant upvote, haha! Seriously though, I think, like this guy suggests, if you avoid cookies on your site or use same site, your fine and cors is mostly a waste.
- jub0bs 2y ago[dead]
- egberts 2y agoI know that CORS is stupid. It took a CORS expert from W3C to answer this convoluted CORS question. https://stackoverflow.com/questions/62289103/same-origin-request-causes-access-control-allow-origin-doesn-t-match-error-th https://stackoverflow.com/questions/62289103/same-origin-req...
- fmajid 2y agoYou really should be using Content-Security-Policy to block untrusted scripts. And anything you do not host yourself should be untrusted, no matter how much your marketing department whines they want to include Google Tag Manager.
- cxr 2y agoCSP is a poorly designed, dangerous, user-hostile standard that should have never been written, let alone implemented. Better idea than "using Content-Security-Policy to block untrusted scripts": don't link against untrusted scripts.