XMLHttpRequest cannot load https://www.[website].com/

Multi tool use
XMLHttpRequest cannot load https://www.[website].com/
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.[website].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?
does it issue CORS headers? perhaps if you shared some code it would be easier to see
– Jaromanda X
Feb 22 '16 at 12:25
Plausibly. Which department should I ask to find out? I just do the backbone.marionette stuff mostly...
– Peter David Carter
Feb 22 '16 at 12:26
You should have enough with what I provided you
- yes ... it's a CORS issue– Jaromanda X
Feb 22 '16 at 12:30
You should have enough with what I provided you
Yeah. I suppose the organisations of departments isn't always uniform anyway, so it is possibly a nebulous question but I would like to know a bit of the backend/routing/sys-admin stuff at my company and this seemed like a good excuse to familiarise myself so if there are problems in future I can help out.
– Peter David Carter
Feb 22 '16 at 12:32
6 Answers
6
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.
<canvas>
<iframe>
The standard scenario that demonstrates the need for the SOP can be demonstrated with three characters:
https://www.[website].com/
http://localhost:4300
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
.
XMLHttpRequest
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).
<img>
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:
… but the browser has no way of knowing if either of the above are 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 was given to a different website.
Why the Same Origin Policy only applies to JavaScript in a 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.
Why you can display data in 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.
<img>
CORS
The Access-Control-Allow-Origin
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.
Access-Control-Allow-Origin
A basic implementation would just include:
Access-Control-Allow-Origin: *
… 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 you can dynamically generate that based on the Origin
request header to permit multiple, but not all, sites to access it.
Origin
The specifics of how you set that response header depend on Bob's HTTP server and/or server-side programming language. There is a 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.
Access-Control-Allow-Origin
Obviously granting permission via CORS is something Bob would only do only if either:
If you are also Bob in this scenario, then the specifics of how you add CORS permission headers will depend on some combination of your choice of HTTP server software and what language you are using for server-side programming (if any).
Mallory can't add this header because she has to get permission from Bob's site and it would be silly (to the point of rendering the SOP useless) for her to be able to grant herself permission.
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:
enctype
Note that "custom headers" include Access-Control-Allow-Origin
and other CORS response headers. 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.
Access-Control-Allow-Origin
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.
OPTIONS
GET
POST
Access-Control-Allow-Origin
Access-Control-Allow-Methods
Access-Control-Allow-Headers
Alternatives to CORS
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 which 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.
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 they Same Origin Policy grants permission by default. CORS is not needed.
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:
That server-side code could be hosted by a third party (such as YQL).
Bob wouldn't need to grant any permissions for that to happen.
This would be fine 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.
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
If I run local LAN a web server and try to do ajax load from the IP/URL will that work ? I havent tried that yet. as my web server returing json data would be a MCU
– Ciasto piekarz
Dec 23 '16 at 5:09
@Ciastopiekarz — Normal same origin / different origin rules apply. Normal network routing rules apply.
– Quentin
Dec 23 '16 at 12:25
Most complete answer I ve ever read, instead of just a link about cors..
– pungggi
Apr 22 '17 at 18:12
@Quentin - Wow! +1! So what I'm to understand is if Alice uses the CORS extension, the server thinks that her http calls are not from javascript but from a browser extension and treats it like a normal same origin request?
– snippetkid
May 11 '17 at 11:51
@snippetkid — No. In the usual case, the server will send CORS headers in ever response and not care where the request came from. It is the responsibility of the browser to allow or deny access to the data to the JS based on the CORS headers on the response. (Things get a /little/ more complex on the server when it comes to preflight requests)
– Quentin
May 11 '17 at 11:54
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
Also a very useful answer. Wish I could accept two :/ :/ :/
– Peter David Carter
Feb 22 '16 at 12:37
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.
If the server owner does not explicitly prevents it in some way - you can make use of Simple requests.
Note that a 'simple requests' needs to meet several conditions, including only allowing POST
, GET
and HEAD
as well as only allowing some given Headers (you can find all conditions here).
POST
GET
HEAD
If your client code does not set affected Headers 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.
A good indicator for this scenario can be the CORS error including the term preflight
.
preflight
This is a related question here on stackoverflow.
You should enable CORS to get it working.
In case you are getting this error while developing extension for google chrome, simply add-
"permissions": [
"http://www.google.com/"
]
in the manifest.json file.
** Replace Google with your third-party URL.
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
I'm working on the website and it was fine five minutes ago.
– Peter David Carter
Feb 22 '16 at 12:25