81

I recently learned about CORS and got the impression that its purpose is to prevent XSS. With CORS, the browser blocks requests to different domains, unless particular headers are in place.

But if a person with malicious intent injects some JavaScript into a page to steal users' cookies and send them to a URL he controls, all he has to do is add the following header on the server side to make the request work anyway:

Access-Control-Allow-Origin: *

So how does CORS prevent XSS? Or did I misunderstand the purpose of CORS, and it simply has nothing to do with XSS per se?

curiousdannii
  • 350
  • 3
  • 12
Gigi
  • 1,280
  • 1
  • 11
  • 12
  • 4
    `all he has to do is add the following header on the server side to make the request work anyway` - if somebody has access to HTTP header config on the server there are bigger problems than cross-domain attacks. –  Dec 23 '15 at 14:28
  • 15
    He can do that because it's his server (in the scenario I suggested): "a URL he controls". – Gigi Dec 23 '15 at 14:30

6 Answers6

59

TL;DR: How does CORS prevent XSS? It does not. It is not meant to do so.

CORS is intended to allow resource hosts (any service that makes its data available via HTTP) to restrict which websites may access that data.

Example: You are hosting a website that shows traffic data and you are using AJAX requests on your website. If SOP and CORS were not there, any other website could show your traffic data by simply AJAXing to your endpoints; anyone could easily "steal" your data and thus your users and your money.

In some cases that sharing of data (Cross Origin Resource Sharing) is intended, e.g. when displaying likes and stuff from the Facebook API on your webpage. Simply removing SOP to accomplish that is a bad idea because of the reasons explained in the above paragraph. So CORS was introduced.

CORS is unrelated to XSS because any attacker who can place an evil piece of JavaScript into a website can also set up a server that sends correct CORS headers. CORS cannot prevent malicious JavaScript from sending session ids and permlogin cookies back to the attacker.

Scimonster
  • 103
  • 3
marstato
  • 2,237
  • 14
  • 11
  • 3
    Whether or not SOP and CORS were there, any other website could proxy its users' requests. – Damian Yerrick Dec 23 '15 at 15:22
  • 3
    @tepples: But in this case the cookies for the original site will not be sent with the request and thus it would not be possible to read data which only the logged in user can see. – Steffen Ullrich Dec 23 '15 at 15:50
  • @SteffenUllrich That would explain the behavior if the same-origin policy just blocked cookies. But it blocks client-side scripted access even to public resources that the user can access without cookies. – Damian Yerrick Dec 23 '15 at 15:57
  • Correct. But this is how CORS works - as everything else, it has its weaknesses. – marstato Dec 23 '15 at 16:08
  • 11
    Exactly. CORS doesn't restrict or prevent anything. CORS is intended to provide a controlled way to *relax* the restrictions imposed by the same-origin policy. Without CORS, the web would still be just as secure (though not as functional). – Ajedi32 Dec 23 '15 at 16:42
  • 1
    Can't other sites access your public website data indirectly via- the server side? Isn't it *only* preventing willing clients from accessing your websites data while visiting another website? If my understanding is correct, your answer is wrong and this only specifically stops sites from directing a non-malicious user's browser to your site's data via- client side js. – AturSams Apr 13 '17 at 12:01
  • 2
    Yes, they can unless the sensitive data is protected with a login. A foreign website has no access to the session cookies of the "target"/"cors-protected" website. Thus, a malicious server cannot send a valid request for the data - only the users browser and the resource owning party can construct a valid request – marstato Apr 13 '17 at 13:10
  • 8
    The example is misleading. This is not the purpose of CORS. Your rival can make a similar website to your, which on the backend would call your server with proper origin headers, and CORS won't stop it. – Georgii Oleinikov Jul 21 '17 at 08:54
  • @GeorgiiOleinikov Yes, they could. But in that case i can effectively block their IPs without affecting my legitimate users. This *is* the purpose of CORS. You can post your own answer if you think that CORS has a fundamentally different purpose. – marstato Jul 21 '17 at 09:10
  • @marstato Can you block the entire AWS fleet address space? What if some of your legitimate users are using proxy on AWS? The purpose of CORS in my opinion is to relax SOP, and purpose of SOP is to make sure CSRF attacks aren't performed with Javascript – Georgii Oleinikov Jul 27 '17 at 09:36
  • @GeorgiiOleinikov Depending on the use case, yes. Legitimate end users dont have an AWS IP. Generally thats a good point. I havent read up on the W3C documents on that - they will provide clarification as to what the intent behind CORS is. – marstato Jul 27 '17 at 09:39
  • @GeorgiiOleinikov I think the point is that your proxy server could not pretend to be that someone else. i.e. it can't proxy requests to www.example.com pretending to be a logged in user such as Alice as your AWS server does not have access to her cookie information. That is why the CORs adds a layer of protection. – Rambatino Apr 16 '19 at 06:03
27

Cross-Site-Scripting (XSS) is the execution of attacker defined script code in the context of another site. CORS does not prevent XSS, in fact it is unrelated to XSS.

Instead CORS offers a way to weaken existing restrictions on Ajax requests (i.e. XMLHTTPRequest) in a way which hopefully does not introduce more security problems. Traditionally XMLHTTPRequest was restricted to communicate within the same origin, that is it was not possible to sent a request to some external site. This restriction was done so that an attacker cannot do a cross site request and get the result of the request back, because this would allow an attacker to read data from sites where the users was logged in (because session and other cookies are sent with each request to a site).

With CORS this restriction is partly removed. It is now possible to sent an XMLHTTPRequest to another site but the result can only read inside the application if the remote site explicitly added some CORS headers which allow the access. But again, this is not executing script on the remote site and thus this is unrelated to XSS.

Steffen Ullrich
  • 184,332
  • 29
  • 363
  • 424
  • 6
    To be clear, even before CORS it was possible to *send* a request to an external site by using a form. What CORS allows is actually *reading* the response back from a cross-site AJAX request. – Ajedi32 Dec 23 '15 at 16:49
9

CORS and XSS are related, but not directly. The best way to explain it is by example: we shall consider 3 servers (your_bank.com, api.your_bank.com, badguy.com*) and 1 client (your browser).

  1. You are logged into your_bank.com (your browser holds authentication cookies).
  2. Your_bank.com makes transactions by sending AJAX requests to api.your_bank.com using yet more cookies (held in the browser). Normally your browser's SOP would block this request, but instead CORS (granted by api.your_bank.com) allows it.
  3. You see something shiny at badguy.com, and visit that page.
  4. Badguy.com attempts transactions by sending AJAX requests to api.your_bank.com using the cookies for that domain held in your browser.

At step 4, your browser (which is not compromised) owns the "Origin" header sent to api.your_bank.com. If CORS is correctly configured, this step will be blocked. Your browser, being the owner of the cookies and request headers, is gatekeeping access to other sites.

* The badguy.com site may be legitimate, but suffer from an XSS issue.

Daniel
  • 99
  • 1
  • 2
  • 2
    _"this step will be blocked"_ I agree that the _read_ will be blocked (i.e. the malicious origin cannot retrieve sensitive information from your bank account), but _writes_ currently aren't blocked by the browser (so CSRF may be in play here) – multithr3at3d Jan 14 '20 at 22:21
  • This is an excellent answer, in plain language I can understand. – Dean Jul 18 '20 at 18:56
  • I think this post may be more describing a cross-site request forgery (CSRF or XSRF). I'm not a security expert, but from all I have seen, XSS is more commonly used to refer to the likes of it being possible for a hacker to inject client-side script, e.g., if a website does not escape user data when displaying it in HTML. XSS can be mitigated also be headers though: the `Content-Security-Policy` header may be used to help with XSS such as by preventing inline scripts. – Brett Zamir Jun 07 '21 at 15:41
  • 1
    This answer is wrong, I do not understand why it has upvotes. If CORS is configured correctly, the step will not be blocked. The browser will not let badguy.com read the contents of the response. That is all. badguy.com can still send requests to api.your_bank.com. – Koray Tugay Aug 01 '21 at 22:57
  • 1
    @KorayTugay While you are technically correct (the best type of correct!) in some circumstances, requests with side effects *must* be "preflighted". This will block the step. I direct the interested reader to https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS and https://fetch.spec.whatwg.org/. However, the standards are not easy to read, and I will happily edit if a correction is needed. – Daniel Aug 03 '21 at 02:05
6

CORS does not protect anything, SOP (Same Origin Policy) protects something instead. SOP protects the target domain and the browser user.

In fact, CORS weaken existing restrictions of SOP to help website developers to use shared data from other origins.

Keaser
  • 161
  • 1
  • 1
3

The browser uses SOP (same-origin policy) to protect the user. SOP/CORS does not to protect the services. CORS is a way of the original domain informing the browser that other domains are trusted.

By default, browsers block JS requests made from a.com to b.com.

b.com can publish CORS headers to notify browsers that a.com is trusted (e.g. facebook.com can publish that their messenger.com domain is trusted)

Good browsers block cross origin scripts to protect users. If b.com publishes CORS with certain trusted domains, the browser allows those domains to access services at b.com. If the browser didn't block these for the user, a user could access innocent-looking-malicious-site.com which could access facebook.com services on the user's behalf and get access to secure cookies and other information.

Loose Relation to XSS

If a legitimate site has been compromised by an XSS attack, the SOP/CORS/browser combination can protect the user if the legitimate site's domain name isn't published in the CORS header.

SOP/CORS can't protect a site from being compromised by XSS, but it can help the user if they access an XSS compromised site.

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

Added clarifications pointed out by user jub0bs

Micah B.
  • 139
  • 4
  • 1
    This should be the accepted answer. An API is not protected by CORS or any allow headers. It is a restriction that the browser imposes to protect the user (one that can be disabled pretty easily). eg. an API service can still be accessed via nodeJS even without allow * – phocks Nov 06 '20 at 10:31
  • 1
    *The browser uses CORS to protect the user*. No. It's the opposite. The SOP protects users, and CORS is a mechanism to relax some of the restrictions of the SOP. – jub0bs Jul 30 '22 at 11:43
  • *By default, browsers block JS requests made from a.com to b.com.* Not true. Browsers don't block all such requests. As an example, open your console and run `fetch("https://example.com", {mode: "no-cors"})`. Your browser will prevent the client from reading the response, but the browser will send the request. – jub0bs Jul 30 '22 at 11:52
  • @jub0bs Thanks for the clarification, but running fetch in a console is not the same thing as making a request from one site to another. – Micah B. Aug 02 '22 at 20:40
  • @MicahB. Yes it is. If you open your Console tab while you're on `https://stackoverflow.com` and use `fetch` to send requests to `https://example.com/foo`, the `Origin` header of those requests will be `https://stackoverflow.com`. My point stands. – jub0bs Aug 03 '22 at 08:43
2

CORS configuration of your site can allow non-simple requests of your UI to your backend services and at the same time help preventing CSRF (not XSS) (against your site) in case user uses a secure web browser.

By default (when no CORS configuration is set for the site) modern browsers don't allow such requests, which is to prevent CSRF. That is called same-origin policy.

With XSS the inserted malicious js accesses resources on the same web site (origin) so CSRF has no play there.

Basically CORS allows your website js frontend code to access your website backend with the cookies and credentials entered in your browser while your backend stays protected from some other site's js, asking client browser to access it (with the credentials user has already obtained).

This is when Control-Allow-Credentials: true is set (which allows browser to send cookies and basic/gssapi/napi auth). I'm still not sure how CORS helps without this option. See my question "https://security.stackexchange.com/questions/148313"

akostadinov
  • 555
  • 3
  • 8
  • *CORS can help limit impact of XSS to the vulnerable site* How? – jub0bs Jul 30 '22 at 11:41
  • @jub0bs, actually my wording is not good. If you have some suggestions to improve, let me know. It's more about proper CORS configuration of the web site can help prevent XSS, provided client browser behaves according to standards. – akostadinov Aug 04 '22 at 09:04
  • Because I don't know what you had in mind exactly, I'm not sure I can offer a better formulation. – jub0bs Aug 04 '22 at 09:41
  • 1
    @jub0bs, I amended that paragraph, let me know if it is clear now. – akostadinov Aug 04 '22 at 13:12
  • Your second paragraph reads like you're mixing up CSRF and XSS... I just don't understand the alleged connection between XSS and CORS. – jub0bs Aug 04 '22 at 16:00
  • 1
    @jub0bs, thank you for pointing this out! There is actually none connection as you stated. Do you see anything fishy still? – akostadinov Aug 04 '22 at 17:01
  • Your answer is better but, all things being equal, configuring a server for CORS never makes it safer against CSRF. See [this other comment of mine](https://security.stackexchange.com/questions/108835/how-does-cors-prevent-xss/175654?noredirect=1#comment546027_237362) and perhaps [this tweet](https://twitter.com/jub0bs/status/1544366638446907394). – jub0bs Aug 04 '22 at 19:56