19 ms·
Developers don't understand CORS
- jonstaab 7y agoTotally agree. Something about CORS and the resources out there makes newcomers think that it's something the client has to do differently. I thought this when first doing cross-origin stuff, and thought it was just me until my dad (programmer for 30 years) got stuck on it the exact same way. Also, the author makes a good point that `Access-Control-Allow-Origin: *` is pretty dangerous. I hadn't really worried about it in the past, because "I don't care who calls my api, they aren't authenticated". But if malicious client code got a hold of a user's session (using XSS or what have you), I'd be open to them steering my user's session and doing horrible things. Definitely going to review my current projects with this in mind. Edit: of course, if I have an XSS vulnerability, they'd be able to do that from my domain anyway, so CORS doesn't 100% fix the problem. XSS is bad.
- corey_moncure 7y agoI for sure haven't mastered CORS. What would you use instead of that? Suppose you're doing something like client-side Blazor that calls to a WebAPI project. How can you improve security by restricting the origin of access requests when your client is open to the public?
- jonstaab 7y agoI'm not familiar with Blazor or WebAPI, but if you're not expecting requests from client-side javascript specifically, you can just use `Access-Control-Allow-Origin: null`, since non-browser clients don't respect CORS anyway. If by "open to the public" you mean "open to requests from any client domain", CORS isn't going to help. In that case I'd probably have api clients pre-register a whitelist of domains that they're planning to make client-side requests from, so you can check the domain against the whitelist and dyanamically build your allow-origin header.
- theturtletalks 7y agoCan you point me to some documentation for dynamically allow-origin header? I’m working on open sourcing our frontend and so if users have their own frontend on their own domain, how do we allow those calls to our backend with CORS? If we turn CORS off, is this a security issue? From the frontend, we send a JWT with the header and check this for protected routes on the backend.
- icebraining 7y agoIs your frontend a static webapp that communicates directly from the browser to your backend, or another server that talks to your backend?
- theturtletalks 7y agoYes frontend is a Next.js app and the backend is a GraphQL server.
- jonstaab 7y agoCORS is really pretty simple, it's getting the threat model that is tricky. Some docs on Allow-Origin here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Ac... and a more complete walkthrough here: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS Dynamic allow-origin sounds magical, but is really straightforward. You just look at the `Origin` header of a request (e.g., in express `req.headers['Origin']`), compare it against your database of whitelisted origins, and if it's in there, return it as the value of `Access-Control-Allow-Header`. If you don't have any relationship with the folks using your frontend, I'd just "turn it off", that is, use "Access-Control-Allow-Origin: *". It's a security issue only insofar as you don't trust the third party that owns the web frontend to handle their users' data securely, either by introducing their own security vulnerabilities, or by hijacking users' sessions themselves. The big question I think is whether the third party's users are your users too, in which case you're responsible to vet the third party to protect your users. If you're just a backend for whatever-the-heck, just make sure you have a good terms of service for the api so you're not assuming responsibility for other people's mistakes/malice.
- modethirteen 7y agoAccess to an API should be managed by a proper authentication or token validation scheme. However, protecting your users' authenticated API sessions, which are presumably initialized by the forementioned authentication scheme, is what CORS enables. CORS, when implemented correctly, ensures that a session is not hijacked by a malicious website's JavaScript in order to call your API in the context of the session (effectively masquerading as the user who authenticated with your API). This scenario assumes that there is an authentication session cookie, tied to your API domain, that the browser would pass along with any request to your API domain (of course there are SameSite cookie and third party cookie blockers that can mitigate these situations as well, but perhaps "trusted" cross domain requests are desired in this use case) With CORS allowing traffic from anywhere on the web, you can't reliably trust that the authenticated sessions to your API are not being used in phishing / side channel attacks: I discover your are authenticated on site on foo.example.com and I send you a link to my website, evil.com. Evil.com includes JavaScript to request data from an API on foo.example.com. Your browser executes the JavaScript and makes the request and gets a response payload, and since I'm a jerk I then post that same payload to my own endpoint on evil.com to capture the data. Of course this all assumes that you WANT your API to be accessible cross origin. If you provide an API as a product this is common, since it allows other developers to build web apps against your API. If that is not a use case, then same origin policy (and no CORS headers from the API server) is sufficient to prevent malicious domains from doing bad stuff with your users' authenticated sessions.
- mehrdadn 7y agoCould you give a realistic example where it wouldn't lead you to have a bigger problem on your hands? I think that'd be extremely helpful.
- modethirteen 7y agoThe company I work for provides embeddable JavaScript "web widgets". Our customers are companies, and their customers are consumers (we are business to business to consumer company). We host somewhat personal data specific to those consumers, and as such, the data should only be accessible by those consumers. So, we provide the data API that these web widgets communicate with, and the web widgets themselves can be embedded on our customers' own websites (some-company.com). However, the customer can decide exactly which hostnames can embed the widget (through a control panel we provide), and these hostnames ultimately become the `Access-Control-Allow-Origin` value we provide with every API response. Perhaps they want it on foo.some-company.com or bar.some-company.com -- it's really up to our customer where they want these widgets to be embedded. By doing this, the customer knows that no other website can host these widgets, thus exposing their consumers' data to a phishing attack as I outline here: https://news.ycombinator.com/item?id=20405169 https://news.ycombinator.com/item?id=20405169
- takinola 7y ago| Also, the author makes a good point that `Access-Control-Allow-Origin: *` is pretty dangerous. But what is the alternative when you have a script that is going to be deployed on multiple sites that you do not control? Which origin do you specify? This is the scenario which always trips me up and results in kludgy workarounds.
- jrochkind1 7y agoI _think_ that is an the appropriate use for `Access-Control-Allow-Origin: `. It would be up to you that only the URL for such scripts (not your entire site) have `Access-Control-Allow-Origin: ` , and to make sure that there is nothing malicious JS can do with `Access-Control-Allow-Origin: *` at those particular URLs. Which is confusing to figure out, it's true, because the whole thing is confusing, indeed.
- zek 7y agoI think the generally accepted solution to this is to set the allowed origin dynamically (IIRC nginx can do this) by looking at the request host header on the options request. If the origin is in some allowed list then you return that origin in `Access-Control-Allow-Origin`
- anderspitman 7y ago> Something about CORS and the resources out there makes newcomers think that it's something the client has to do differently I think that "something" is the fact that the client does the blocking. Generally the servers are perfectly willing to provide the data. Heck, if you sniff the packets, you could even look at the data blocked by CORS (assuming you're working around TLS). It's especially confusing at first that tools like curl work no problem, while browser block everything.
- jonstaab 7y agoYes, that's definitely a big part of it. Test it all with curl or your language's http client, then put it in the browser and it breaks? Must be the client's fault! Which it sorta is. But only because it's a client that doesn't belong to you — you're controlling it on the user's behalf. It doesn't help that when you're developing on your own machine, you're user and the developer, and you of course trust yourself.
- jrochkind1 7y ago> But if malicious client code got a hold of a user's session (using XSS or what have you), I'd be open to them steering my user's session I think the point of this stuff is that, if the user's session is stored in a cookie, and malicious javascript can send HTTP requests to your site (that will use whatever cookie is already present) and read the responses -- they can steer your session without needing to get a hold of a user's session using XSS or anything else. They already HAVE a hold of the user's session, because they can control the browser, which does. The point of cross-origin restrictions is to prevent JS loaded from one site from steering the user's session on a different site. (Maybe among other sorts of attacks). CORS lets you disable those protections. `Access-Control-Allow-Origin: ` disables them entirely. I could have some of this wrong, I find this stuff confusing too. But I believe they do not need to "get a hold of a user's session (using XSS or what have you)" in order to steer a user's session under `Access-Control-Allow-Origin: `
- jonstaab 7y agoI guess that's what I meant; XSS would give them the user's session implicitly on my domain, regardless of CORS. CORS prevents them from using that from another domain, which is valuable, but moot if you already have a breach.
- jrochkind1 7y agoOK, I think I was confused about what "XSS" means or how you meant it or I was thinking about it differently. The important point though: You don't need any pre-existing vulnerability on your site in order for "Access-Control-Allow-Origin: *" to create a vulnerability. This stuff is sure is confusing to talk/think about though.
- jillesvangurp 7y agoDepends what you are trying to do. If you are offering an API for third parties to use, Access-Control-Allow-Origin: * is pretty appropriate. It basically communicates "I don't care where you call me from". Same with content on a CDN (fonts, css, etc.). Of course serving executable content like that is a bad idea; but, even so, people seem to trust certain domains with things like jquery. WIth images, fonts, or other static content the risk is arguably fairly limited except for the fact that browsers tend to have all sorts of nasty bugs with malicious content overflowing buffers thus leading to arbitrary code execution. But of course the elephant in the room is that doing things with headers adds a lot of friction for developers. Now their simple application has a devops component. E.g. modifying nginx to add that header or trying to make AWS CloudFront forward CORS headers is just a royal pain in the ass. It's also very fragile because these things break easily and are rarely covered by integration tests because these things tend to be specific to infrastructure and environment.
- rmbryan 7y agoMaybe we don't understand CORS. Here's a fact-based starting point to learn about CORS: https://en.wikipedia.org/wiki/Cross-origin_resource_sharing https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
- phkahler 7y agoNot a web dev. Can anyone tell me what CORS is ultimately used for? Not the literal technical details, the higher level what does it enable sites to do? And is that for them or their visiters?
- dillonmckay 7y agoSo, javascript requests made from one site to another would be allowed/prevented from returning the information to the browser session. It can still be abused to exfiltrate data.
- mehrdadn 7y agoAlso not a web dev, but if I'm remembering it correctly (someone please correct me if I'm wrong), the way I understood it was: Whenever your browser sends any request to any site, it sends the cookies(/other auth data) associated with that site along with it. In other words, cookies are fundamentally just associated with the receiver, not the sender. So the "solution" is for the receiver to block requests from the wrong sender, since otherwise any site could send authenticated requests to any random site. [Edit in response to comment below: I should've mentioned more here, but I understand what happened was browsers introduced the Same-Origin Policy to prevent this from happening, and introduced CORS as a dynamic bypass mechanism for that, which, unless you implement OPTIONS, can get you these half-baked insecure situations where requests still get sent and executed, but the client JS doesn't get to see the responses.] To me this whole mess is stupid because the premise shouldn't be true in the first place (why the heck should a cross-origin request send auth data? cookies etc. should be "contained" to whatever domains the original site restricted them to), but that's apparently The Way Things Are, and so here we are: browsers do something completely unexpected and insecure, and we blame devs for getting caught off-guard and not protecting against a security hole browsers introduce. (Yes, I have Opinions on this. Please tell me exactly where I'm wrong, because I suspect I might be, but I have yet to figure it out.)
- dillonmckay 7y agoSo, it depends on the request type, GET vs POST and others. Before the client does the request for data, it does a preflight request via OPTIONS to determine what is allowable (is this domain allowed, this type of call). If it is allowed, it can send and request cookies on the requested domain in the current standard. However, this is not supported in older browsers, so the request will just work. In newer browsers, without the preflight check, the server still receives and replies to the request, but the reply is ‘ignored’ by the browser and throws an error.
- arve0 7y agoZoom does not need CORS-headers to fix the vulnerability, rather make the web server running on localhost drop requests with wrong origin header.
- jrochkind1 7y agoHmmm.... never thought about this but now thinking about it... does anyone need CORS? Can server-enforced access controls on "Origin" substitute for CORS in all cases?
- mderazon 7y agoThe server responsibility of CORS is also about making sure the browser accepts the cross origin request (in case it's a valid origin). If it won't send the correct headers back, the browser will drop the request Yes, the server can drop the request or return an error, but that's just half of it. If it wants the browser to accept the request, it has to explicitly say it by using the CORS headers.
- jrochkind1 7y agoAh, right. But why not have browsers allow cross-origin requests, but let an individual server just deny it based on origin header? I guess because we don't trust servers to do that, we need "don't allow by default, let the server opt-in" instead of "allow it by default, let the server opt-out", because too many servers would not opt out.
- arve0 7y agoIf you need access to the users data on another service, without having their credentials on the other service, CORS is the correct choice. > Servers can also notify clients whether "credentials" (including Cookies and HTTP Authentication data) should be sent with requests. https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
- MetalGuru 7y ago> The webserver listening in on localhost:19421 should implement a REST API Is this server started by Zoom? In order to implement an endpoint, they’d have to ship a server along with the client. And this server would always be running? Is this not overkill for such a small feature (being able to click a link)
- outworlder 7y agoYes, it is overkill. And insecure. All that to avoid a confirmation box.
- greenshackle2 7y agoThey already ship a server along with the client. It's already always running. The author is explaining how they could have done it more securely. I think everyone here including the author would agree it's a ridiculous solution for this "feature".
- csours 7y agoI certainly don't understand CORS. I've read about it several times and I don't remember what I read. It's like CORS has a teflon coating that prevents it from sticking in my mind. I know what CORS is for and why you need it, but I have no idea how, where, and when to use it.
- leowoo91 7y agoAs a motivation to use: To prevent other sites using your resources, causing you an extra bandwith cost.
- davidw 7y agoBack in the day, we used to use some Apache redirect magic to redirect to, say, an image of our choosing when the Referrer header was wrong. I had a relatively polite 'hey, you can see this image here:' message. Other people redirected to less friendly things.
- jefftk 7y agoYou can still do this. The Referer header is sent by default on requests, and you can make your server interpret it to do anything you want.
- gmfawcett 7y agoThis is true unless the referring URL is secured (HTTPS), and the destination URL is not. In that case a conformant user-agent will leave Referer out. https://tools.ietf.org/html/rfc7231#section-5.5.2 https://tools.ietf.org/html/rfc7231#section-5.5.2
- jefftk 7y agoTrue, though you should run HTTPS on your site. Which means you'll get the Referer unless the other site or the user's browser has been configured to suppress it.
- anaphor 7y agoThat is because CORS is a kludge to work around the fact that we decided to use session cookies "because developers understand it easily" instead of just re-doing everything. See https://w3c.github.io/webappsec-cors-for-developers/#cors https://w3c.github.io/webappsec-cors-for-developers/#cors > Enter Cross-Origin Resource Sharing. The challenge when designing CORS was how to enable web applications to request and receive more cross-origin permissions, without exposing existing applications to new attacks. By the time CORS arrived on the scene there were already billions of HTTP resources in use by a wide array of applications beyond the traditional browser. Many of those resources relied implicitly on the original permission table. For example, they might expose a privileged endpoint on an intranet, but check for a special HTTP request header that only a non-browser or same-origin client could set, to protect themselves from CSRF-type attacks. The design of CORS couldn’t suddenly make all those existing applications vulnerable; it needed to evolve the web platform in a backwards-compatible way. If we had started with the assumption that you can make requests and receive responses from any site to any other site, then we would not have the confusing mess that is CORS. > The story behind * Why does the * mode of CORS behave so differently than the credentialed mode? Given the already long history of web vulnerabilities attributable to abuse of ambient authority, there were two schools of thought about how to expand the web platform with cross-origin requests. One camp proposed extending the already-familiar cookie model to authenticate to cross-origin resources. The other camp felt that ambient authority was a mistake in the architecture of the web, and advocated for cross-origin requests free of any ambient credentials or origin-based authentication. (Such requests, they also argued, could be exempt from the Same Origin Policy entirely, as they would be equivalent to loading from an unprivileged proxy.) The XDomainRequest object in Microsoft Internet Explorer 8 and 9 retained some of this style - it had no support for credentials, only anonymous requests, although it also used the same Access-Control-[...] headers. > The familiarity and compatibility of the cookie-based credentials model of CORS eventually won more favor with developers than re-designing their applications in a capability-security style. (https://www.w3.org/TR/capability-urls/ https://www.w3.org/TR/capability-urls/) As a compromise, the anonymous request mode was retained as a “subset” of CORS. Unfortunately, the subtle differences in architectural style that persisted and the choice of * to represent such requests has been a consistent source of confusion.
- 7y ago
- p2detar 7y agoRecently, I was working on an issue where our new frontend client was not receiving custom response headers from the server API. It turns out I had to expose headers first using 'Access-Control-Expose-Headers' [0]. Neither me, nor the frontend dev have heard of that response header before and we thought we knew something about CORS. [0] https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Ac...
- edejong 7y agoThe reason the developers didn't use CORS is because active mixed content isn't allowed. You simply cannot call 'http://localhost' http://localhost' from a https domain. For a medical SaaS application which needed to communicate via USB I created a self-signed certificate during installation and added it to the trust store to be able to call active content on localhost. Previously, we used NPAPI (which, when used correctly was more secure than the current plugin architecture), but that got deprecated. Ask yourself why many developers need this path. The reason is that creating plugins for various web-browsers is a very expensive ordeal, with Firefox and Chrome having a completely different ecosystem. Moreover, in my opinion the plugin ecosystem is less secure than having good engineers take the localhost path (with challenge-response token authentication and origin hostname validation, obviously).
- chrisfosterelli 7y agoThis is discussed in the post text, but happy to elaborate here in more detail here! Here is the patch links from Firefox[0] and from Chrome[1] which they specify that active mixed content policies do not apply to the localhost, because the w3c specification was updated to specifically allow this behaviour[2]. You might have to use 127.0.0.1 directly. So yes, it is allowed. If for some reason that doesn't work for your app, the post also mention two secure alternatives: the native client can install a self-signed cert, or you can use a browser extension with the native messaging API. You touched on this too! My point here is not the specific example solution -- there's lots of alternatives and yes it depends on the situation and browser support requirements. But NONE of them are a reason to allow requests from every origin. [0]: https://bugzilla.mozilla.org/show_bug.cgi?id=903966 https://bugzilla.mozilla.org/show_bug.cgi?id=903966 [1]: https://chromium.googlesource.com/chromium/src.git/+/130ee686fa00b617bfc001ceb3bb49782da2cb4e https://chromium.googlesource.com/chromium/src.git/+/130ee68... [2]: https://github.com/w3c/webappsec-mixed-content/commit/349501cdaa4b4dc1e2a8aacb216ced58fd316165 https://github.com/w3c/webappsec-mixed-content/commit/349501...
- edejong 7y agoI see it is fixed now. I thought up this work-around back in 2014, when NPAPI was phased out. Spotify and another large player came up with similar solutions.
- jedberg 7y agoIt's not just a lack of understanding but a lack of support in server tooling. I was setting up CloudFront on AWS and kept running into CORS issues. I did all the steps to set the necessary headers, but it still didn't work. I ended up just doing some layer 7 routing to route requests to /api towards the other server that was on the other domain to avoid the CORS issues, because now there is no cross domain request. It seems more secure that way anyway.
- icebraining 7y agoBut were the headers reaching the browser or not? CORS is something strictly for the browsers to parse, so if it's reaching the browser, either the policy is wrong (and you can usually see that in the browser console, when it blocks the cross-domain request) or it's not a CORS problem.
- jedberg 7y agoIt wasn’t reaching the browser.
- icebraining 7y agoSeems like you have to whitelist the headers: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/header-caching.html#header-caching-web-cors https://docs.aws.amazon.com/AmazonCloudFront/latest/Develope...
- jedberg 7y agoI did, but it still didn't work. It was extra complicated because it was coming out of API gateway calling Lambda. But the point is, it shouldn't be that complex and I shouldn't have to dive deep into the docs to make it work. That is as much an impediment to CORS as is the lack of understanding.
- EGreg 7y agoSeriously wondering! Why is Zoom worth $2B and companies are paying per minute plans to host meetings when you can now host your own videoconferencing software easily on your own website or app or intranet using WebRTC, branded, with your own experience, widgets, and it can all be open source? All you need to pay for are dumb TURN servers eg from twilio. Plus it would be far more secure. For example we built https://yang2020.app/meeting https://yang2020.app/meeting You can have stuff like that yourself, for free, no Zoom required. It’s open source SPECIFICALLY what does Zoom provide? People can install wordpress easily, and 30% of the Web has. Why not for videoconferencing?
- leesec 7y agoThis reads so much like the infamous dropbox comment.
- skunkworker 7y agoFor anyone wanting the link. Comment https://news.ycombinator.com/item?id=9224 https://news.ycombinator.com/item?id=9224 Post https://news.ycombinator.com/item?id=8863 https://news.ycombinator.com/item?id=8863
- EGreg 7y agoHow so? It's super easy to just download and put into any website. Look at the demo above. It took us about 3 months of work to get all the quirks out, but anyone can do it. A developer can grab our library but if you don't know how to code, it's just a widget you get off the Internet. And it works on YOUR WEBSITE. This isn't like Dropbox because there is no desktop app.
- leesec 7y agoSo you're wondering why people use something that just works over something that took you (assumedly someone technical) 3 months to get all the kinks out? How long do you think it would take a non technical team or company to get it up and running?
- zenexer 7y agoThe author suggests that using CORS to allow https://zoom.us https://zoom.us with http://localhost:19421 http://localhost:19421 is possible. This is factually incorrect. Mixed content policies prevent the http: origin from communicating with the https: origin. "For very intentional reasons, the browser explicitly ignores any CORS policy for servers running on localhost." That last sentence is incorrect – Chrome does respect CORS headers for localhost webservers. It's only partially incorrect. In most cases, CORS will not work with localhost, at least without a self-signed certificate trusted by the browser.
- chrisfosterelli 7y agoThis is discussed in the post text, but happy to elaborate here in more detail here! Here is the patch links from Firefox[0] and from Chrome[1] which they specify that active mixed content policies do not apply to the localhost, because the w3c specification was updated to specifically allow this behaviour[2]. You might have to use 127.0.0.1 directly. So yes, it is possible and not factually incorrect. If for some reason that doesn't work for your app, the post also mention two secure alternatives: the native client can install a self-signed cert, or you can use a browser extension with the native messaging API. [0]: https://bugzilla.mozilla.org/show_bug.cgi?id=903966 https://bugzilla.mozilla.org/show_bug.cgi?id=903966 [1]: https://chromium.googlesource.com/chromium/src.git/+/130ee686fa00b617bfc001ceb3bb49782da2cb4e https://chromium.googlesource.com/chromium/src.git/+/130ee68... [2]: https://github.com/w3c/webappsec-mixed-content/commit/349501cdaa4b4dc1e2a8aacb216ced58fd316165 https://github.com/w3c/webappsec-mixed-content/commit/349501...
- deleted 7y ago[deleted]
- zenexer 7y agoI'm fairly certain that these patches didn't land until recently, at which point the design decisions were probably already made at Zoom. (I don't know much about Zoom, but that seems like a reasonable assumption.) Additionally, these changes aren't likely to apply to Firefox ESR or IE for a while. In Zoom's case, I highly doubt CORS on its own was a viable solution. Maybe in 2026, a decade after the patch, sure, but in the current climate, it's not reasonable to expect that all users will be using browsers that have adopted these changes in 2019.
- thrusong 7y agoI sort of get it and yet even when I'm sure I've configured it correctly, I'll hit road blocks in Safari, for example, when it works everywhere else as expected. It is such a frustrating experience.
- boudin 7y agoYeah, i'm dealing with CORS issue with Safari right now. On a XHR with a custom header over https, safari fails with a "protocol error" error rather than running the pre-flight request. The same query without the custom header works well. Every other browser (IE, Edge, Chrome, Firefox) handle it well and does the OPTIONS call to ensure I allow this header. If anybody has a solution for that, I'm all ears :)
- neuroticfish 7y agoI'm dealing with frustrating CORS issues right now. We have a CDN intercepting outgoing requests from a request resource and nobody here can seem to figure out how to get it to keep allowed headers for OPTIONS method requests.
- anderspitman 7y agoSounds like something that's going to have to be configured on your CDN. I'm assuming you already checked with them/their docs?
- hn23 7y agoFrom the title I expected a simple explanation how CORS works...my fault..
- MrStonedOne 7y agoThe number one issue with CORS I've found is that merely defining it undoes alot of defaults and most of the top searches on the subject of how to do x in CORS doesn't explain what those defaults are. So you get devs breaking things trying to whitelist something not normally allowed then deciding to cast a wide net to fix those things. The CORS standard needs to be radically redefined from the ground up with developer ease of use as part of the consideration.
- alexchamberlain 7y agoI don't really understand how CORS adds much security wise; it relies on the web browser behaving and respecting your policy...
- brlewis 7y agoIt protects against attacks where the bad actor is trying to get your browser to do something you don't want. It's OK for browser security measures to rely on web browsers to implement them.
- raxxorrax 7y agoWouldn't this be stopped by address translation by routers for normal users? Don't know much about the app itself...
- jrudolph 7y agoCORS is a minefield. It doesn't help that the RFC is incredibly dense. I may be totally missing something, but I've repeatedly wondered though if CORS still has its place in times of SPAs that exclusively use xhr + javascript + some sort of auth token talking to a REST API? Consider this argument: CORS basically ensures that browser and servers cooperate to protect end users from a "smart" user agent that happily throws around cookies and/or auth tokens. Remove cookies and basic auth headers, what's the point of CORS? Happy to hear thoughts from folks more knowledgeable in web security than me. If not, let's please get together to propose an RFC for the CORS-GTFO header (a server header indicating that a browser does not have to do wasteful preflights etc.)
- untog 7y ago> Remove cookies and basic auth headers, what's the point of CORS? The ability to communicate with a domain other than the one your app is running on. For instance, if my site on www.example.com wants to send a POST to www.example2.com, I need CORS. example2.com needs CORS to specify that only example.com is allowed to send a POST to it, not anyoldaddress.com. example2.com could look at the Origin header and refuse connections, but it would be vulnerable to DDOS attacks. Now, if your SPA is entirely self-contained and self-hosted then no, you don't need CORS. But there are plenty of situations where that isn't the case.
- disiplus 7y agoyup, i have a signup form on our website and that signup form calls ajax if the email is in use. without cors i would have to use jsonp or some other workaround.
- throwamay1241 7y agoI don't think the act of sending the POST is blocked by CORS, receiving the POSTed response data is though.
- zer0faith 7y agoRarely does a application actually need to enable CORS. If all of your webcalls are from the same domain YOU DONT NEED CORS. (Chatbots/socket.io) You only need CORS if you need the browser to act as a middleman to pass information back. IE: Credit Card Payment IFRAME If you screw up CORS implementation it just means that anyone can read any information set by your website. https://www.moesif.com/blog/technical/cors/Authoritative-Guide-to-CORS-Cross-Origin-Resource-Sharing-for-REST-APIs/# https://www.moesif.com/blog/technical/cors/Authoritative-Gui...
- mderazon 7y agoNot so rarely. It's pretty common to serve the js frontend code on one domain the apis on a different domain
- z3t4 7y agoJust tried and I get CORS errors when trying to access localhost in Firefox, also on images via xmlHttp ... Edit: It works with image elements! img = document.createElement("img") img.src = "http://localhost:1337/service" Btw, CORS is a PITA when doing pure web apps, apps that doesn't requre a server. I recently made a RSS reader web app, but had to use a CORS proxy. I wonder if there is any way I can use an image element to bypass CORS and read RSS xml that way !?
- duncans 7y agoA little shortcut for this is: new Image(1,1).src = 'http://localhost:1337/service'
- heavenlyblue 7y ago>> I wonder if there is any way I can use an image element to bypass CORS and read RSS xml that way !? The article in question says they used the image dimensions to encode the error codes returned by the server when making a request. I can imagine you could simply encode the payload in the dimensions of the image.
- z3t4 7y agoI was thinking about using img.src to replace xmlReq and Fetch. So that I can fetch sites that I do not own. eg. RSS feeds.
- heavenlyblue 7y agoSo how would you receive the data, then?
- chpmrc 7y agoHow does not allowing CORS make any sense if any other application running on my system can bypass it except the browser? The technique to bypass it is to have a proxy, either local, or remote. Wouldn't it make more sense to simply allow the browser to make any request the app wants?
- untog 7y agoBrowsers are ubiquitous, and they run third party code. That would be a deadly combination for anyone hoping to launch a DDOS attack if CORS protections didn't exist.
- chpmrc 7y agoThe same could be said about operating systems. In fact when just replacing "Browsers" with "Operating systems" your sentence would still hold true.
- untog 7y agoNot really. Third party code that you haven't installed does not run in an operating system at the click of a button. It does in the browser. By the logic you're outlining there's no reason to sandbox a browser at all, since it's no different to an operating system. Experience suggests that would not be wise.
- jimmychangas 7y agoThe default cross-origin blocking behavior is useful for many things, such prevention of data exfiltration via XSS vulnerabilties. CORS is a way to relax this behavior.
- why-el 7y agoThat's certainly true, you are making the leap of faith that your customers are running standard compliant browsers, which, all considered, is true. All the techniques you mention require you to break either the customers or some element along the network chain to the server, and once you do, well, CORS is the least of your problems.
- greg7mdp 7y agodude, I've been a developer for over 30 years and I haven't ever heard of CORS. Let alone understand it.
- miguelmota 7y agoWell just until 2014 CORS became a W3C recommendation. Before that CORS was mainly in Draft mode and loosely supported by browser vendors. I do find it surprising that you've never dealt with CORS in the last five years if you've ever deployed any production grade API or web service.
- jrochkind1 7y agoI find in most discussions of CORS, developers don't understand the _threat model_ it is meant to be guarding against. I'm not sure I do, I get confused, although I think I have in the past. I think better docs are needed, I haven't found really good educational materials that begin with the big picture (threat model, what are we actually trying to do here, what things are we trying to guard against, what things are out of scope for CORS to try to guard against), which to me is the necessary foundation to get your head around it: Where you need it, and what you will want to make it do.
- pawelk 7y agoI met many developers who thought that CORS can guard access to API endpoints, completely missing the fact that one can just use a client that doesn't follow CORS. E.g. "lets restrict access-control to our API endpoints so it only responds to requests from our website". This is a valid use case, but it's meant to protect a web browser user. An evil website won't be able to request their profile data from our API, and CORS makes it possible to relax this protection to allow our other web property on a different domain access to this information. If someone wants to scrape the API, they can just use cURL and not care about CORS at all.
- arendtio 7y agoI absolutely hate the current same-origin-policy (SOP) we have and therefore CORS. In the end, CORS is a way to work around the problems the same origin policy creates. Yes, I know there are good reasons why we have it, but in my opinion, it is the wrong solution to that problem. I mean, the biggest problem the SOP solves is that some website could trick the browser into sending an authenticated request to your site/API. And while the SOP just kills interactions between different origins completely, I wonder why they didn't just go with not allowing the browser to include any state it got from an origin earlier when the request comes from a different origin. That way it would be possible to do requests between different origins, but without the problem of hijacked authentication. Instead, we got this same origin policy which completely isolates different origins and makes browsers a lot less powerful than other HTTP/S clients and drives developers mad. Edit: Feedback appreciated.
- anaphor 7y agoNot sure why you're getting downvoted. It's a valid point. I think it's because people intuitively think of access control as an answer to the question "Who are you?", which means your authentication credential needs to be sent with every request to a given site. The alternative solution is to use "capabilities" which are a way of accessing a given resource by the very fact that you possess a reference to it. E.g. the google drive feature where you can say "anyone with the link can {view,edit,comment,etc}". The downside is obvious though: it would require everyone to adapt to this model, and rewrite all of their apps to use it instead of the session cookie model. Not gonna happen without a massive effort (see ipv6 rollout for an example of the effort required for something like this).
- arendtio 7y agoThanks for the response. Yes indeed, there would be the cost of change. But if we want the web to be truly decentralized it doesn't make much to disallow any cross-origin interaction by default. After all, cross-origin requests are a normal thing on the web. The problem is that browsers make credentials available to websites that shouldn't have control over them. It is like removing all doors from a house because otherwise, the stupid neighbor would give the keys (you gave him for watering your plants) to anybody that would ask.
- deleted 7y ago[deleted]
- DGAP 7y agoThis article is a great illustration to me as well of how hard it is to do security right even if you're a professional, much less a developer who's mostly responsible for implementing features not building secure systems. The internet is rife with self-proclaimed experts, all offering directly contradictory advice as loudly as possible on best practices for security.
- Beldin 7y agoThe webserver listening on localhost:19421 should [...] set a[n] Access-Control-Allow-Origin header with the value https://zoom.us https://zoom.us. This will ensure that only Javascript running on the zoom.us domain can talk to the localhost webserver. If you create a single-purpose webserver, you can really handle this better than asking the client to play nice via an HTTP header.
- garganshum 7y agoThis is my high level overview of CORS. 1. The website JS is served from a domain say "website.co" to the browser when you visit it. 2. If this JS tries to make a XHR to a domain that is NOT "website.co"(not the origin of JS) the browser first sends a preflight request (OPTIONS) asking for "guidance" from this second domain. 3. The Web Server on second domain responds with "a request" to block/allow XHR calls from JS served from certain domains. 4. The browser chooses (by default) to not make the GET/POST call if the JS domain(website.co/*) is not in "Access-Control-Allow-Origin" header. There are other nuances but that is it really. Things to note 1. The browser enforces CORS. Not the web server. You can disable this enforcement with a flag in both Chrome and FireFox. 2. Since only browsers enforce CORS, other tools(cURL, PostMan) will successfully make GET POST request regardless CORS config on the webserver. 3. If you could intercept (using a proxy) and change headers in response to preflight request you can bypass CORS on browsers. 3.
- greenshackle2 7y agoMostly correct, but the browser may or may not send an OPTIONS request depending on the request type, headers, and more. https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Simple_requests https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Simpl...
- deleted 7y ago[deleted]
- Waterluvian 7y agoI'm in this semi-special place in web dev where almost everything I make is for a captive audience on local networks. So it feels like there's entire segments of web dev that I've only learned to subvert. CORS is one of them. All I really learned is that you can't make calls to services on another domain unless that service allows it via CORS. Eg. Every robot I want to websocket to has to be cool that the web application originally loaded off of (and in a way is owned by) the central server.
- cakoose 7y agoThe blog post author doesn't understand CORS either! Their advice on how to fix the problem is wrong: > So what would a secure implementation of this feature look like? The webserver listening in on "localhost:19421" should implement a REST API and set a "Access-Control-Allow-Origin" header with the value "https://zoom.us" https://zoom.us". This will ensure that only Javascript running on the zoom.us domain can talk to the localhost webserver. "Access-Control-Allow-Origin" doesn't block the request from going through, it just prevents wrong-origin Javascript from accessing the response. The original vulnerability actually just a slight variant of cross-site request forgery (CSRF) -- "wrong site request forgery" :-) For the localhost server to detect wrong-site requests, there are two simple options: 1. Use a CSRF token. This requires a shared secret between the localhost server and the Zoom website. 2. Check the "Origin" header. This requires that the request be an HTTP POST, which is what they should be. (Note: If you're determined to use some CORS machinery, you could build something more complicated based on pre-flight requests, but there's no point.)
- ChrisCinelli 7y ago> "Access-Control-Allow-Origin" doesn't block the request from going through, it just prevents wrong-origin Javascript from accessing the response." On a GET request (like the one generated by a IMG tag) and all the other cases that do not require a pre-flight request ( https://www.w3.org/TR/cors/#preflight-request https://www.w3.org/TR/cors/#preflight-request ) this is correct. Are we clear on the thread model and what Zoom is trying to do? As far as I know, Zoom wants to make "joining a meeting" as easy as clicking a link. I do not think Zoom wants people to be logged in a zoom account in order to join. And what Zoom should try to avoid is to have random people joining meetings and website forcing actions on the laptop of the people. A simple fix is to use a GUID or any other long not-guessable string for the meeting id. And, of course, do not expose any other potentially dangerous endpoints beside the one that starts the meeting. In general it should not be about either CORS or CSRF. There are better ways to start a video call communicating with a plugin than exposing a port on localhost and using <img src="localhost:12345/a-command?aParameter=12345" /> to communicate with it.
- kortilla 7y ago
- jusob 7y agoYet another explanation of CORS. The basic security in we browsers is based on SoP: Separation of Origins. To simplify, there are number of actions that can be done within an origin (a domain, to simplify) that are prevented across origins (across domains, to simplify). CORS is way for bridge 2 different origins, i.e.e to allow some specific actions between 2 different origins. One example: by default, XHR requests can only send a specific set of HTTP headers to a different origin. If b.com want to accept the header X-Special-Header from a.com, it has to whitelist it - Access-Control-Allow-Headers: X-Special-Header, Access-Control-Allow-Origin: a.com. On a.com, before the web browser makes an XHR request to b.com that includes the header X-Special-Header, it has to check whether b.com authorizes it or not. I sends an OPTIONS request to b.com and check for the HTTP response headers Access-Control-Allow-Origin and Access-Control-Allow-Headers. Since CORS is a way to bypass the Separation of Origin basic security model, you should be careful with it. For example, you may allow any site to get read your content, i.e. trigger a CSRF request on behalf of the user logged in to bank.com, and with Javascript be able to read the page content, including the account number because bank.com set the CORS to authorize any remote site to do anything, basically putting bank.com in the same origin as any other domain.
- WhitneyLand 7y agoBypassing it all (be careful) with no-cors? Relatively recent Chrome debug messages about a no-cors "opaque" option, suggest the client has the ability to bypass the server rules without using any kind of proxy. Is this true? Maybe I didn't notice it got added as an option when fetch was added in addition to the old style XHR requests?
- thundergolfer 7y agoC -
- poglet 7y agoThe Firefox extension "CORS Everywhere" has let me test my web app on my computer without having to mess around with headers. This was while using PowerShell Polaris to create a website.
- Animats 7y agoOne of the side effects of CORS is that you can't display most off-site images through WebGL. Displaying an off-site image through <img> is allowed. Otherwise ads would break. But you can't bring the same image into the WebGL system. I hit this trying to display map tiles. The map tiles are on a server that doesn't send any CORS headers. A simple 2D display of the map works fine. But using a 3D library that allows rapid movement, perspective views, and flyover hits a CORS block. I can force through that with a browser add-on, but that's just for testing. Incidentally, CORS-plugin for Firefox has a major security hole. You give it a URL to allow, but, randomly, it switches invisibly to "all URLs" and opens a security hole.
- squiggleblaz 7y agoThe statement is false. CORS - cross origin request sharing - only adds permission. CORS could allow you to display off-site images through WebGL, but it cannot prevent it. CORB - cross origin request blocking - is what prevents you from doing it. This sounds pedantic, but it seems that till people understand that browsers implement CORB unless a server implements CORS (or in whitelisted/legacy circumstances), they cannot understand their problems or the solutions. This is largely the fault of browser vendors, who seem to act as if everyone understand CORB and their only task is to educate you about CORS.
- bamboozled 7y agoMost developers I interact with don't even understand something as fundamental how a TCP connection works (not blaming) let alone something as abstract as CORs. What are you going to do? Some things are just complicated and it's hard to find good people who actually bother to understand these systems, it's what separates the best from the rest.
- DrOctagon 7y agoIf an HTTP API is GET request only and there is no authentication for the API, think public weather info API, is there any risks with having "Access-Control-Allow-Origin: *" set? I've tried to get my head around CORS a few times without much luck.
- syntheticcdo 7y agoACAO:* is appropriate for a publicly accessible, unauthenticated request.
- hardwaresofton 7y agoSecurity practices that are hard to use correctly are often misused/not used at all can be worse than if they weren't there at all (because of the false sense of security). On this axis, and the axis of adoption CORS is a huge failure (despite the fact that when used correctly it does increase security). The crypto security space has the same issues with hard-to-implement standards and impossible-to-configure libraries -- the likelihood of misuse/overly permissive settings in frustration is really dangerous. I don't know if there is/was a reasonable alternative (there probably isn't really), but I guess at this point the only thing to do is to write better documentation/guides on how to use CORS.
- systematical 7y agoThesis: Developers don't understand CORS. So I read it. All along the author does not attempt to explain CORS to me. I then Google CORS, and think I do understand it already, but this guy is telling me I don't, but completely fails at explaining why I don't. Maybe I don't understand CORs, but the author didn't help anyone with this piece. This received 508 upvotes...how?
- ops4c0d3 7y agoOne of the most enlightening threads I've come across in awhile. Thanks for the solid explanations
- wwarner 7y agoBest CORS reference is MDN [1]. Here's a piece of unsolicited advice: avoid CORS if you can. For user facing web apps, put your APIs behind a proxy. For a dev environment in which you want to mix local assets with production assets, use a proxy. In general, if you can't solve a cross origin problem with a proxy server, then you should really stop and reconsider what you're trying to do. CORS is full of unpleasant subtleties, as many of the comments below illustrate. Different browsers implement CORS differently. Want to cache that preflight request? You'll use the header `Access-Control-Max-Age` for that. Except Chrome doesn't respect respect that header; the cache TTL is actually hardcoded to 10 minutes [2]. Except, according to this bug [3], Chrome will respect your cache headers starting in July. [1] https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS [2] https://stackoverflow.com/a/23549398 https://stackoverflow.com/a/23549398 [3] https://bugs.chromium.org/p/chromium/issues/detail?id=131368 https://bugs.chromium.org/p/chromium/issues/detail?id=131368
- simplecomplex 7y agoCORS is useless, unnecessary, insecure, and essentially only serves to annoy developers. Par for the course for all web tech from the last 20 years. Another turd in the tower of shit that is JavaScript.
- Thorrez 7y agoIf attacker.com makes a request trying to read bank.com/my-bank-account-number should attacker.com be able to do that and read the response? The same origin policy blocks the response from being read. Now that we've established that by default a.com cannot read a response from b.com , CORS allows b.com to relax this restriction so that a.com can read from b.com . This allows one website to communicate back and forth to the server of a different website, making certain APIs easier. I don't consider that useless.
- sirsuki 7y agoTo be that guy... forget CORS. All localhost servers have a pinned public key. The zoom.us site has the private key. It passes along a signed request. The local server then validates the signature! How is that so hard? Oh wait, I just described CSRF!! Zoom, here is your egg. Now promptly smash it on your face; thank you.
- Thorrez 7y agoWouldn't that allow the token to be replayed? Attack scenario: 1. Attacker installs zoom. 2. Attacker starts to join meeting foo. 3. zoom.us creates a signed request saying "join meeting foo" and gives it to Attaker. 4. Attacker takes that signed request and sends it from attacker.com to localhost inside Victim's browser. 5. Victim's zoom native app gets the request, validates the signature, and joins the meeting. I think it can be modified to be safe if there's a key exchange between zoom.us and the native app, and zoom.us signs the key exchange with its private key. But this seems hugely overkill compared to a simple Origin check, or even compared to a traditional XSRF token (via a cookie on localhost).
- Twisell 7y agoMy point of view as a SQL developer reading a article about something front-end by curiosity: Yet another article about some <acronym> ranting about usage and misconceptions about <acronym> without even caring to explain in the first 20 paragraphs what the hell <acronym> mean or is supposed to achieve in the first place. You are free to re-use and adapt this sentence for each new <acronym> like feature trending at any point in time. PS: My bad it was actually described in the last sentence of the citation inserted in the third paragraph.
- microDude 7y agoOne thing I never understood was why server1.mycompany.com (origin) cannot make a GET request to server2.mycompany.com?
- pault 7y agoFor cases where shared hosting issues subdomains for users I reckon.
- akidomowri 7y ago> A security guy isn't 100% correct ALL DEVELOPERS DON'T UNDERSTAND
- mrmonkeyman 7y agoThe browser rejects it sure. But what if I write my own custom nonstandards compliant browser?
- mrwww 7y agoMany beginner tutorials on web development breeze by "how to disable cors" as the most natural obvious thing to do, usually when wanting to call your own API on a subdomain. I think because it sometimes "gets in the way" and how to properly work with it requires slightly more planning than just disabling, developers fall into bad habits.
- felxh 7y agoI think the advise in the article and various comments here won't work, for the simple reason that Safari does not allow ajax requests from non localhost origins to localhost. I suspect this is the real reason they used an image request.
- khnov 7y agoFrom what I see, the author do not understand CORS neither ! He blames pple and do can't even give the explanation of CORS using his words
- sandstrom 7y agoAn annoying thing with CORS is that one cannot allow all paths for an origin. I.e. there will be pre-flight requests for every new path that requests are made to in a REST API, making the response caching useless. Apparently to work around some bug in Microsoft ISS server. But this has also greatly increased the performance hit from CORS under some common usage scenarios, which is sad. http://lists.w3.org/Archives/Public/public-appformats/2008May/0039.html http://lists.w3.org/Archives/Public/public-appformats/2008Ma...
- justanegg 7y agocors is not security, it's just a sanity check on top of real security
- patrickaljord 7y agoDevelopers understand CORS, it's just like any security measure, it goes against the infinite list of features devs are pressured to implement.
- vkaku 7y agoCORS and preflighting, ugh, just adds more developer friction. That's just my opinion on it.
- nottorp 7y agoWould it have been so hard to spell out what CORS means? So people who don't do web development don't have to wade through the acronym soup?
- ozim 7y agoThat is not about CORS it is about "DevOps", implemented in a way: let just developers do what they do on their local machine so we don't spend money on Ops people and security people because our developers are smart enough, we pay them 400k a year. Setting up some local shizzle on production server that is callable from frontend ... Just stop, you can have microservices that listen on local interface but please call it from behind api gateway. If you have some different domains you need to use then yeah make subdomains? I don't know just hire some Ops people and make them work together with Devs.
- Timpy 7y ago> Original security article: briefly touches on CORS > Follow up article: that thing about CORS is not right > Hacker news top level comments: that article's not quite right > First child comments: tlc is also not exactly right I feel like I understand CORS even less now. Article title is right, I don't understand CORS.
- calibas 7y agoI think the issue with understanding CORS is that you first need to understand same-origin policy and exactly when it applies. CORS is simply a method for bypassing same-origin policy. You also need to understand how a CSRF attack works. Once you grasp both of these things, then you have the base for how and why CORS exists. Until then it's mostly an annoyance.
- formatkaka 7y agoWere we supposed to understand it? Voodoo programming is the solution to CORS.
- kyberias 7y agoVery arrogant post that doesn't explain CORS or offer any useful links for understanding CORS.
- martin_a 7y agoAt this point I don't want to understand CORS. Put together a little script package this week, threw in some Vue and a Bootstrap and put it on our fileserver. Now the Font Awesome icons won't load due to CORS errors. I don't want to spin up a server for 500 lines of HTML/JS. I don't want to download the fonts, fiddle around in Bootstrap etc. CORS is broken or the web itself has become broken if we need integrity checks and cross origin protection for using fonts.
- cooperaustinj 7y agoUse a CDN!
- martin_a 7y agoSo my scripts will randomly go down with the rest of the internet? Great idea!
- yyyk 7y agoBase64 should allow you to do it. It's logical to limit remote font loading, even moreso than js. There used to be quite a few RCE bugs involving fonts on Windows and Adove.