Hacker News new | ask | show | jobs
by eejjjj82 660 days ago
CORS is designed to protect the server data. It's a tool that gives servers a control mechanism to tell browsers "who can access my data".

Imagine that your banking website used a standard JSON+REST API with cookie based authentication to trigger & validate a transaction request.

When a request to `fetch` or XMLHTTPRequest is made from ANY site, the browser will still populate cookies for 3rd party sites.

So without CORS, then someone might be able to create a landing page, which in the background triggers a `fetch` or `ajax` request to your bank's transaction endpoint. For 99.999% of people this wouldn't be effective because they are probably not a customer of this bank and are not logged in at the time of the request. But for some very tiny fraction of users, the browser would be tricked into populating the Cookie header from a previously created session in a different tab and would send this request.

The Origin header in the CORS preflight is a signal from the server to the browser that 'yes, this request is safe for you to construct'. This way the browser doesn't let the malicious web page "trick it" in the first place to send the bad request.

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

3 comments

>So without CORS, then someone might be able to create a landing page, which in the background triggers a `fetch` or `ajax` request to your bank's transaction endpoint. For 99.999% of people this wouldn't be effective because they are probably not a customer of this bank and are not logged in at the time of the request. But for some very tiny fraction of users, the browser would be tricked into populating the Cookie header from a previously created session in a different tab and would send this request.

Are you talking about an attack where the attacker tries to control the victim's bank account by initiating a transfer? That's a CSRF attack. CORS and the same origin policy don't prevent that attack by default. The browser will still send the request the request populating the cookie. The same origin policy will prevent the evil site from reading the response, not from making the request. To protect against this attack the bank needs to implement CSRF protection (e.g. checking the Origin header).

> When a request to `fetch` or XMLHTTPRequest is made from ANY site, the browser will still populate cookies for 3rd party sites.

I think this is the problem here? Just send the request without cookies if CORS doesn't allow it.

(I also think third-party cookies were a mistake in general, and it would be a good thing if they were removed. There were some plans but well, Google.)

>Just send the request without cookies if CORS doesn't allow it.

The problem is how will the browser know whether CORS would allow it or not? It could send a preflight, yes. In the current rules that's only done for complex requests, not simple requests. You seem to be suggesting preflights be sent for all requests. That would balloon the number of requests, adding RTTs, slowing down page loads.

E.g. if example.com embeds an image from imgur.com and the browser happens to have a cookie in the imgur.com cookie jar, should the browser send a preflight request first to decide whether to attach cookies to the request or not? That preflight would slow down the page load. In the current rules, the cookies are simply attached, with no preflight required for that type (simple) of request.

Simple requests could still work without preflight. What I suggest is, complex requests (e.g. fetch()) that don't require cookies (e. g. using credentials: "omit" [1]) shouldn't preflight either.

[1]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/U...

By the way, the default fetch `credentials` value ("same-origin") doesn't send cookies to third-party websites either. Why CORS still applies here is a mystery to me.

Edit: some requests can work without preflight, but there are some absurd limitations (GET/POST only, and request body can't be a JSON): https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simpl...

And to clarify, my point here is: I think CORS is a security theater. The only part that really helps is Access-Control-Allow-Credentials (and that's only because third-party cookies are still a thing).

>By the way, the default fetch `credentials` value ("same-origin") doesn't send cookies to third-party websites either. Why CORS still applies here is a mystery to me.

There are other types of authentication besides cookies. E.g. TLS client certs. Does the browser not send a TLS client cert for fetch requests that don't send credentials? In some cases that could double the number of TLS sockets: one socket with a client cert and one socket without a client cert.

Another type of authentication is sites that only allow requests from certain source IP ranges. Or similarly, services run on a local LAN that aren't exposed to the public internet (e.g. a router's admin panel that's only accessible to devices on the LAN) or a service running locally on your machine serving on localhost. Someone might want to run a service locally and allow foo.com to make requests to it and read their responses, but block evil.com from making requests to it and reading the responses. And there might be no cookies involved with that local service, because it's running locally on the user's machine and thus doesn't need cookies to know who the user is. Of course we also need to consider DNS rebinding attacks. Those can be protected by Host header checks or Origin header checks, but Origin header checks only work for requests that send an Origin header, which aren't all requests.

>I think CORS is a security theater.

The same origin policy and CORS have 2 aspects:

1. Preventing evil.com from reading the content of email.com . I don't think this is security theater. This is very useful for security and doesn't have a bunch of confusing caveats. CORS headers can be used to allow good.com to read the content of email.com if email.com wants to allow that. That's useful for certain functionality.

2. Preventing evil.com from sending certain types of requests to email.com . This has a bunch of confusing caveats about which type of requests are allowed and which types are blocked. So this isn't super useful. However I don't think I'd call it security theater. Here's how I think this restriction was created: As browsers added more and more ways to send requests, they wanted to avoid introducing vulnerabilities to websites that were created in the past before those types of requests could be sent and that relied for security on the assumption that those types of requests couldn't be sent. So the browsers implemented preflights to make sure that these new types of requests they were creating wouldn't introduce vulnerabilities to old websites.

> Does the browser not send a TLS client cert for fetch requests that don't send credentials?

I think it doesn't. From MDN: “Credentials are cookies, TLS client certificates, or authentication headers containing a username and password.”

> Another type of authentication is sites that only allow requests from certain source IP ranges.

This one can be tricky, yeah. Ideally such devices would check Origin header, but that ship has sailed I guess.

---

But I think it should be pretty safe to allow cross-origin requests that:

- don't use credentials and

- don't go to a private network.

This means that evil.com can GET https://email.com/ without CORS, but the response won't be personalized to user (so they can read the landing page but not your messages). They can also POST https://email.com/api/send, but that wouldn't do anything as again we don't include credentials.

good.com will send a request with credentials and in this case CORS should be checked indeed.

If evil.com tries to POST https://192.168.0.1/reboot we require CORS too since it's in a private net. If evil.com tries to GET https://192.168.0.1/config we don't send preflight but check CORS headers on the response before allowing to read it.

If your site is on public net and you authorize users solely by IP – that's on you.

> I think this is the problem here? Just send the request without cookies if CORS doesn't allow it.

Yup, very obviously a problem and it's why we got CORS :) But just because it's a problem, doesn't mean we can remove it from all browsers and call it a day, it'll break huge parts of the internet.

So in true internet engineering fashion we do what we always do, pile yet another layer on top of the stack to fix some issues from the previous layer (and add some more complications for the next (future) layer).

This is mostly correct, but one thing that's worth pointing out is that CORS doesn't protect anything, but it 'loosens' the protection that the browser has by default. The S in CORS stands for sharing, not security.