67

I've been reading in the last couple of days about CORS and in a lot of places it's mentioned as it is a "Security" feature to help the world from cross domain forgery.

I still don't see the benefit and the reasoning for CORS. Ok, browsers will do a preflight request / server will validate the origin. But an attacker can easily create an HttpRequest top-bottom with whatever Headers(Origin) he wants and he will get access to the resource.

How is CORS helping and what's the benefit of it?

0

7 Answers 7

85

I'll start my answer by saying that many people misunderstand the Same Origin Policy and what CORS brings to the table.

Some of the up-voted answers already here are stating that the Same Origin Policy prevents cross-site requests, and therefore prevents CSRF. This is not the case. All the SOP does is prevent the response from being read by another domain (aka origin). This is irrelevant to whether a "classic" CSRF attack is successful or not.

By "classic" I'm referring to the types of request that were possible before CORS came about. That is, the types of request that can be sent via HTML forms as well as XHR (e.g. GET or POST without custom headers).

The only time the SOP comes into play with "classic" CSRF is to prevent any token from being read by a different domain.

Of course, now we have CORS and all sorts of cross-domain requests are possible such as PUT and DELETE, CORS does in fact protect against these by requiring a pre-flight. However, generally speaking CORS is not providing greater net benefit because the reason this functionality is available in the first place is due to CORS.

All CORS does is relax the SOP when it is active. It does not increase security (except perhaps allowing cross-domain resource sharing to be standardised and prevent developers from introducing flaws with something like JSONP), it simply allows some exceptions to take place. Some browsers with partial CORS support allow cross site XHR requests (e.g. IE 10 and earlier), however they do not allow custom headers to be appended. In CORS supported browsers the Origin header cannot be set, preventing an attacker from spoofing this.

I mentioned domains were different origins. Origins can also differ by port and protocol when talking about AJAX requests (not so much with cookies).

Finally, all of the above has nothing to do with forged requests coming directly from an attacker, for example with curl. Remember, the attacker needs to use the victim's browser for their attack. They need the browser to automatically send its cookies. This cannot be achieved by a direct curl request as this would only be authenticating the attacker in this type of attack scenario (the category known as "client-side attacks").

The benefit of CORS is that it allows your domain to allow reads from another trusted domain. So if you have http://data.example.org you can set response headers to allow http://site.example.com to make AJAX requests and retrieve data from your API.

14
  • 6
    This is the most correct answer. Also nobody seems to be mentioning that most modern CORS libraries let you whitelist what Origins you want to allow. Everything I read seems to assume you should just be allowing all Origins which usually is not the case for most people. Mar 6, 2016 at 20:30
  • 1
    All the SOP does is NOT prevent the response from being read by another domain! It doesn't even allow browsers to send a preflighted request to another domain.
    – Daniel B
    Mar 7, 2018 at 7:32
  • @Daniel What kinds of requests are blocked by the SOP?
    – curiousguy
    Jun 25, 2018 at 7:58
  • I have some thoughts regarding POST requests without custom headers and with a standard Content-Type header value (e.g. application/x-www-form-urlencoded). For this requests, the browser (at least, Chrome) following the CORS policy WILL NOT make a preflight OPTIONS request and will send the POST request right away. This means that if a user visits the site of an attacker and this malicious site makes this POST request via AJAX with the withCredentials options set to true (thus, sending session cookies), then CSRF would be successful. Am I right? May 4, 2019 at 16:09
  • 1
    @jub0bs: True, I used "cookies" as the most common example, but it could be a different form of auth such as digest, basic, certificate based, or, as you mention by request IP address only. I answered a similar question along those lines here in regards to CORS . Sep 1, 2021 at 11:33
15

You're mixing things up. CORS is not meant to protect your application from crafted http requests, it's meant to protect you from a certain kind of attacks that "steals" the user's cookies or access tokens, by checking what sites can access your resource.

It's mostly used to protect your server/application from cross-site request forgery, where a malicious site will do a request on behalf of the user, possibly with malicious intents (credentials change, money transfer...), exploiting the fact that the browser will send any login and session cookie still alive and valid for your site.

If CORS is correctly configured, the ajax request of the attacker's site will be rejected, as, by default, it will only accept requests by the same site.

This DOES NOT mean you should not sanitize your inputs, and only protects you from a certain type of CSFR attacks. Should the attacker get your user's cookies/access tokens he will be granted access anyway, and that's why most authentication processes should use SSL as an additional layer of protection.

PS: This assumes the browser your user is using is up to date, has no flaws and is correctly obeying the same origin policy.

EDIT: As for preflight requests, this is an additional measure to be sure the site is granted access, and are not done for all cross-origin requests

4
  • This answer really cleared things up for me. Now I understand that it is the requested third-party resource that needs to allow the request, not the server that generated the requesting page.
    – alexw
    Dec 14, 2015 at 1:39
  • 10
    @Sebastiano, CORS is not meant to protect you from CSRF. (CSRF would stil be possible via <img src= and <form action= regardless of CORS.) CORS is meant to protect you from the site you are currently visiting, preventing them from accessing and reading the response of other sites (Gmail / banking sites) that has your sensitive details.
    – Pacerier
    Jan 23, 2016 at 18:55
  • 2
    CORS is not for protection, but a resource sharing. To some extent it is just the opposite of CRSF. The former allows for cross-origin requests, the latter forbids (or prevent some malicious) cross-origin requests. Also CORS request is generally not rejected by the server, but the response from the server "rejected" by the client, i.e. the browser. So SOP does not necessarily prevent CRSF, as clarified in @SilverlightFox's answer.
    – wlnirvana
    Feb 20, 2020 at 7:57
  • 2
    @alexw please don't get confused by this answer. It's not correct. CORS makes your application LESS secure. Any of the security benefits this answer talks about, are actually already there by default because of the Same-Origin Policy. See my blog for a good explanation: levelup.gitconnected.com/… Dec 13, 2020 at 4:50
3

I've been reading in the last couple of days about CORS and in a lot of places it's mentioned as it is a "Security" feature to help the world from cross domain forgery.

You either misunderstood the benifits of CORS or may be you have read that in some amateur blogs done by developers who are more worried about how to make it work than how to make it safe (if you understand what I mean), because CORS rather makes your web application vulnerable to such attacks (CSRF) when you open cross-origin requests from the attacker's origin by using CORS with the following header: Access-Control-Allow-Origin: *

How is CORS helping and what's the benefit of it?

CORS was born to lighten the restrictions of the SOP for trusted requests only. But the problems start exactly with that trust. An attacker could do harm through the origins by forging malicious requests through GET and POST methods for example, and may expose you even DNS rebinding

5
  • 4
    What is the relevance of DNS rebinding in the context of CORS? If a DNS rebinding attack is successfully being carried out, then information is already being leaked (regardless of CORS headers). If CORS is incorrectly set up, then information can already be accessed without DNS rebinding. In either case, I don't understand why DNS rebinding deserved to be mentioned in your answer. Did I overlook anything?
    – Rob W
    Aug 26, 2015 at 16:02
  • @RobW If you implement CORS as it is, I mean without making the necessary to check the origin and host headers have the same host name then you are vulnerable to DNS rebinding.
    – user45139
    Aug 26, 2015 at 17:14
  • 2
    If you always reply with Access-Control-Allow-Origin: *, then the resource is already public, so DNS rebinding doesn't add any value. Could you give an example (requests & responses) where DNS rebinding and CORS together result in a security issue, which really requires both components in the attack?
    – Rob W
    Aug 26, 2015 at 17:18
  • @RobW what a resource author check when implementing CORS? By instinct he is likely (and we speak about developers) the origin header only. The origin headers displays from where the cross-origin request comes from, a developer forgets to check the host header, there comes the problem. If you want a proof of concept you may ask that in a different post (in order not to lead my answer off-topic: i mentioned that as an additional information to the OP, he asked only about CSRF)
    – user45139
    Aug 26, 2015 at 17:26
  • 6
    By the way your answer is phrased, DNS rebinding sounds like a serious vulnerability that is highly relevant to CORS, and somehow relevant to CSRF. In order to carry out an attack that abuses origin whitelists, the attacker has to control one of those origins. DNS rebinding is not going to help over there. If the attacker controls the origin, then the only thing where DNS rebinding could be used is to steal cookies that were set after a CORS-enabled request with credentials via an attacker-controlled host name. That attack sounds a bit far-fetched. Did you have anything else in mind?
    – Rob W
    Aug 26, 2015 at 18:01
3

Does it make sense to summarise all this as follows:

  • SOP (Single Origin Policy) ensures CSRF attacks can't be made from within a modern, up to date, browser due to the fact that the attacker would have to be POSTing from another domain.

  • CSRF (Cross-Site Request Forgery) tokens ensure that dangerous POST requests can't be made outside of the browser (where SOP doesn't apply, e.g. using curl), because they have no access to authentication data in user cookies outside of a shared browser experience.

  • CORS (Cross-Origin Resource Sharing) can be used to relax restrictions on SOP to browsers, but only if the resource server allows it through CORS headers. Therefore it has the potential to actually weaken security if used incorrectly.

2
  • 1
    Your first point is not accurate. CSRF attacks can be made because for simple GET/POST requests, all SOP does is stop the browser being able to read the response, the request still gets sent. The rest sounds ok. Dec 13, 2020 at 4:54
  • Second point also seems not accurate. CSRF attacks happen within the browser, because the browser will automatically send the session cookie to the trusted site. Requiring an additional CSRF token ensures the request cannot be forged. When using curl, you need to provide the session cookie yourself (that you don't have), so an attacker cannot make a successful request regardless.
    – henk
    Jan 14, 2022 at 10:29
2

As for this part,

browsers will do a preflight request / server will validate the origin. But an attacker can easily create an HttpRequest top-bottom with whatever Headers(Origin) he wants and he will get access to the resource.

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

Additionally, for HTTP request methods that can cause side-effects on user data (in particular, for HTTP methods other than GET, or for POST usage with certain MIME types), the specification mandates that browsers "preflight" the request, soliciting supported methods from the server with an HTTP OPTIONS request method, and then, upon "approval" from the server, sending the actual request with the actual HTTP request method. Servers can also notify clients whether "credentials" (including Cookies and HTTP Authentication data) should be sent with requests.

As much as i am aware, if you use HTTP methods like 'PUT' instead of 'POST' and because making a cross-domain request using 'PUT' as the specified method will always be preceded by a pre-flight request checking to see if the Origin is allowed, this can prevent attacks in certain situations. This is because the origin can't be spoofed by the attacker as modern browsers don't allow client side scripting languages such as Javascript to set the 'Origin' or any custom headers cross-domain, the attack will fail.

Hope that helped.

3
  • It seems CORS helps protect against CSRF only comparing services with misconfigured CORS to services with properly configured CORS. As for services that do not interpret the Origin request header, do not respond to OPTIONS and do not include CORS headers, both old and modern browsers will stop malicious scripts from sending PUT requests against such: w3c.github.io/webappsec-cors-for-developers/#cors
    – eel ghEEz
    Jul 12, 2017 at 15:38
  • 2
    "non-standard HTTP methods like 'PUT'" what? PUT is certainly standard. Sep 20, 2018 at 18:24
  • @EvanCarroll replace "non-standard" with "not simple". PUT cannot be sent via the user's interaction with a browser. Only GET requests (user clicks on a hyperlink, or types something into the URL textbox), and POST requests (user clicks the submit button on a form). PUT/DELETE can only be sent via Javascript, which can execute in the background without the user/victim knowing about it. For more info, read "Why is PUT/DELETE treated differently to GET/POST?" section in medium.com/swlh/simulating-a-csrf-attack-part-2-bf6f378da625 Dec 13, 2020 at 5:02
1

Yes, it is helping, but not really by design.

CORS stands for Cross-Origin Resource-Sharing. It's not really intended for security. CORS is folded into the fetch API, so it's only useful for Javascript (more on that later). By default, fetch() can't grab what's not in the same origin because of the Single Origin Policy (SOP). CORS loosens that up by saying what other origins are allowed to access a resource. Also, XMLHttpRequest behaves the same way.

So, yes it can help block cross-site scripting (XSS) because the resource is trying to be accessed from across another origin. And technically, your server isn't blocking the request. It's browser that doesn't let the request go through by respecting the Access-Control-Allow-Origin header.

But that's only for Javascript. Browsers don't use CORS for Simple Requests.

That means simple GET requests (like fake images) don't get stopped by CORS. Also, POST requests not done in Javascript (ie: forms) don't trigger CORS. You still need protection against that. Security is only as strong as your weakest link, and once your start preventing CSRF at a server-level from Simple Requests, you'll realize that your CORS is just an extra layer that isn't truly necessary, but still nice to have.

1
  • 1
    "Yes, it is helping". No, it's not. For something to "help", it needs to provide more value than what is already available. By default, the Same-Origin Policy is used, and CORS adds no extra security to what is already there, at all. In fact, it makes things less secure by giving you the ability to allow other domains to make requests to your domain. "So, yes it can help block cross-site scripting (XSS)", again, no it can't, because by default, browsers do this anyway because of SOP. "Browsers don't use CORS for Simple Requests", replace 'CORS' with 'pre-flight requests'. Dec 13, 2020 at 5:06
0

None of the answers here address the core of the issue, so I will try.

Update: Actually OWASP offers this simple way to leverage CORS to successfully prevent CSRF: include a custom HTTP request header with your requests, and check for it on the server! Apparently this causes a preflight check, and that whitelists the domain. So that may be enough!

CSRF

An honest user will use a standards-compliant browser so their access and secrets would be only be communicated by the server in response to an authenticated request, eg with a session cookie bearer token, or signed with a private key.

The way cookies work, they used to be sent out with requests to sites even on domains not matching the top-level domain of the current document. Thus, for example, a foreign site could initiate a POST to your bank (eg via a < form > element with an invisible submit button) and take an action if you had a cookie. This whole class of attacks is mitigated when need to run Javascript to sign a request on the client. You can either do this with an HMAC (using a symmetric key stored on both server and client instead of a bearer token like a session cookie) or you can do it with Assymetric Cryptography, eg elliptic curve signatures using a non-extractable private key (see “subtle web crypto” APIs that come with every browser).

If your server expects requests to be signed, you can dispense with anti-CSRF techniques like double-submitting cookies or session nonces, all of which are there to mitigate attacks made possible by relying on a single bearer token (session cookie) to authenticate a a request.

Since your server refuses to honor requests that aren’t properly signed, you don’t need to worry about CSRF anymore. But since a lot of client-side code is simple, eg mere HTML or simple JS, then requests (eg for images, or large POST requests) might not be signed. And thus that web server will still honor requests with just a bearer token / cookie. It is in this case that you want the CSRF protection — at least with a nonce. (Which, by the way, does NOT need to be generated and stored in a session, it can be calculated by taking HMAC of the sessionId cookie, for instance).

Denying Requests

You can go further and instruct your webserver to refuse all requests originating from foreign domains, so that people don’t eg hot-embed your images (even in no-cors mode) in their site. You’ll still be open to DDOS.

In fact, if you want to help prevent DDOS, your server should generate its own session IDs, with expiration dates and sign them with an HMAC so you can quickly reject requests without properly signed session keys. You can do this rejection at the edge, eg CloudFlare workers, or at least in your local proxy (varnish or nginx).

CORS

CORS on the other hand does not by itself prevent the above class of attacks, where a POST request can be submitted with cookies and your server will need to ignore it. Because, for example “simple requests” (from the original CORS spec) that look like GET or POST submitted by a < form > element are sent without any preflight checks! See https://stackoverflow.com/questions/39725955/why-is-there-no-preflight-in-cors-for-post-requests-with-standard-content-type

You need to implement the above mitigations, expecting signed sessions etc. otherwise if a bearer token / cookie is ever stolen then a MALICIOUS user using a MALICIOUS user-agent can send bad requests, using just that bearer token. But, the hope is simply that an honest user won’t easily get their session ID bearer token stolen. Another thing you can do these days on your server is to set the SameSite: Strict attribute in your Set-Cookie header, which should also mitigate any malicious CSRF exploits.

Now, the main purpose of CORS has been to prevent foreign domains from exfiltrating content from your server, and that includes JSONP. The CORS functionality is not to protect the foreign site from your server, such as XSS exploits. Because like all web tech, it is your server that calls the shots, and thus chooses to benefit or not. So if you have, say, copyrighted content, you can require an authenticated request to access the content, and also use CORS to prevent the client code loaded from that server’s domain from reading it and exfiltrating it.

This is all designed so that an honest web end-user using a standards-compliant user agent will be able to view information from your server, while the server hosting a remote website, even one embedding your content, is not.

Overall Security and Economic Analysis

When it comes to attacks, modeling threats and incentives, the question you should ask is “cui bono?” Who benefits?

CSRF and CORS, like most Web browser technologies was originally designed to help Web SERVER operators secure their networks and provide a mechanism to give assurances to honest users of their networks.

An honest user will tend to use a mainstream, standards-compliant user-agent (eg browser) in order to access websites. It is in this environment that an honest user will authenticate a session, by entering a password, signing a webauthn payload with a private key, or whatever.

On the other hand, a malicious user may create a fake account and use a browser that doesn’t comply. The goal is to isolate such a user’s attacks so that they can only really hurt themselves. A major theme there is to make everything a zero-sum game, and not allow any “credits to be minted for free”, such as free clicks on ads (click fraud), free tier (DDOS), free messaging (SPAM), etc.

For a much broader approach to micropayments and economics, preventing a whole host of attacks, and actually monetizing digital content across websites in an open and interoperable manner, see https://qbix.com/ecosystem

3
  • The OWASP advice doesn't leverage CORS. Setting a custom header was possible before CORS. In a direct sense, CORS relaxes security rather than strengthening it. In an indirect way it can increase in though by discouraging e.g. JSONP, but that doesn't apply in the CSRF scenario here. Basically CORS adds extra functionality, but the CORS rules support "classic" functionality as to not introduce any extra weaknesses by default, such as not allowing cross-domain headers without consent of the server. May 1 at 9:11
  • It was my understanding that preflight requests didn't exist before CORS was introduced, though. May 3 at 16:37
  • That's right, because we didn't need them. The preflight is only to get the consent of the server to use CORS. Without CORS there was no need for a preflight as cross domain requests were not possible in JavaScript. CORS enabled JavaScript in domain A to speak to domain B (and read the response), which is why the extra Access-Control-* headers were introduced to allow this access. May 3 at 18:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .