I have spent hours trying to access a resource from a different domain.
http://www.nczonline.net/blog/2010/05/25/cross-domain-ajax-with-cross-origin-resource-sharing/ which is referenced in other SO posts states that by simply using XMLHttpRequest in a browser that supports CORS, CORS policy should be enabled. However I am still getting
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://www.nczonline.net/. This can be fixed by moving the resource to the same domain or enabling CORS.
When using it in Firefox 34 which according to http://caniuse.com/#feat=cors should be sufficient.
I am trying a simple example from http://www.nczonline.net/blog/2010/05/25/cross-domain-ajax-with-cross-origin-resource-sharing/
<script type="text/javascript">
function log(msg){
var output = $('#output');
output.text(output.text() + " | " + msg);
console.log(msg);
}
function createCORSRequest(method, url){
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr){
xhr.open(method, url, true);
log("'withCredentials' exist in xhr");
} else if (typeof XDomainRequest != "undefined"){
xhr = new XDomainRequest();
xhr.open(method, url);
log("XDomainRequest is being used");
} else {
xhr = null;
log("xhr is null");
}
return xhr;
}
function main(){
log("Attempting to make CORS request");
var request = createCORSRequest("get", "https://www.nczonline.net/");
if (request){
request.onload = function(){
log("LOADED!");
};
request.send();
}
}
$(window).load(function(){
main();
});
</script>
And I am getting the following output:
Attempting to make CORS request
'withCredentials' exist in xhr
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://www.nczonline.net/. This can be fixed by moving the resource to the same domain or enabling CORS.
Trying it on fiddle https://jsfiddle.net/zf8ydb9v/ gives same results. Is there another lever somewhere that needs to switched on to be able to use CORS bBesides using XMLHttpRequest?
The same origin policy (which prevents making of CORS requests) is there for your security, not the security of the server: it prevents malicious scripts to access your data on other servers using your cookies.
So, if you want you can still disable it at your own risk, on your browser.
In Chrome/Chromium, if you want to disable the same origin policy you can start it with the --disable-web-security option:
chromium-browser --disable-web-security
Anyway, if you want it to work for your users, they will not able to make CORS requests if they have not disabled this security check in their browsers (which is discouraged if not for testing).
As noted in other answers, some servers can purposely allow this kind of requests if they believe this can be useful and not harmful for their users, and they can do this with the Access-control headers.
Moreover, if you still want to find a way to provide this kind of functionality to the users, you might make a Chrome extension, which is not bound to the same origin policy.
A common solution to this is to make the cross origin request server side, returning the result to your application. You should be careful coding this: passing the url to fetch to the server will easily cause security concerns for your server side software. But if you have to fetch the same url every time, you could hard code it server side, in PHP would look like something like this:
<?php
echo file_get_contents("http://your_cross_request/");
?>
then making an ajax request to this page (which will be from the same origin) will return the content of the remote url.
CORS headers are found in the response sent by the server to your request. If the requested page isn't sending the header, it doesn't matter what you did with the request in a stock browser, you'll get a security error
The relevant CORS headers look like this, the last being the most important one
Access-Control-Allow-Credentials: false
Access-Control-Allow-Methods: GET
Access-Control-Allow-Origin: *
I tried opening "nczonline.net" and when I looked at the response headers I did not see any of these, so the server is not configured to permit being loaded in this way
If you are an administrator of that website, you may want to consider adding the required headers to your responses, perhaps being specific about permitted origins rather than using the wildcard
If you're simply trying to demo your code and want to try it with a third party, load a page which does send these headers e.g. developer.mozilla.org
Related
I am a little confused on the security provided by CORS. Below are two HTTP requests that are practically the same, one works the other does not, one is via curl the other is javascript in the browser.
Terminal
$ curl https://www.google.com/
--> Returns a page
Browser:
// Open the console in the browser (or spin put localhost)
const xhr = new XMLHttpRequest();
xhr.open("GET", "https://www.google.com");
xhr.send();
--> CORS Error
Try again:
const xhr = new XMLHttpRequest();
xhr.open("GET", "https://www.google.com");
xhr.setRequestHeader("Access-Control-Allow-Origin", "*");
xhr.setRequestHeader("Access-Control-Allow-Methods", 'GET,PUT,POST,DELETE,PATCH,OPTIONS');
xhr.setRequestHeader("Access-Control-Allow-Headers", 'Origin,Authorization,Content-Type,X-Auth-Token');
xhr.setRequestHeader("Access-Control-Allow-Credentials", 'true')
xhr.send();
--> CORS Error still
So I am guessing the google.com server has it set to only accept requests from the google domain. But when I curl from my terminal that isn't part of the google domain I get a 200 response with HTML, ect.
So why would the server respond to my terminal with no domain, but doesn't respond when I use javascript in the browser?
Thanks ^.^
CORS is a security feature that in the end is implemented by your browser. Which is why you would never see CORS errors when curling from a terminal. See also: this post from mozilla
which says:
Cross-Origin Resource Sharing (CORS (en-US)) is a mechanism that uses additional HTTP headers to tell a browser to let a web application running at one origin (domain) have permission to access selected resources from a server at a different origin.
CORS is a feature provided by the browser.
CORS is a mechanism which aims to allow requests made on behalf of you and at the same time block some requests made by rogue JS and is triggered whenever you are making an HTTP request to:
a different domain (eg. site at example.com calls api.com)
a different sub domain (eg. site at example.com calls api.example.com)
a different port (eg. site at example.com calls example.com:3001)
a different protocol (eg. site at https://example.com calls http://example.com)
Please find the attached article - https://medium.com/#baphemot/understanding-cors-18ad6b478e2b
I am trying to send a request to my api deployed in Heroku. I used an XMLHttpRequest object to fire a request to the api. I am trying out a simple
GET and no tricks. However, I receive this error:
XMLHttpRequest cannot load https://xxx-xxxx-xx.herokuapp.com/api/foods/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.
Which is normal for Chrome. However, I wanted to do this the way Postman handles it. How should I make the request to the api so that it allows everything?
I used this Chrome extension and it worked.
https://github.com/vitvad/Access-Control-Allow-Origin/
What I was able to figure out that it is basically setting this rule:
rule = {
"name": "Access-Control-Allow-Origin",
"value": "*"
};
However, when I try to set it using xhr.setRequestHeader() method, it doesn't work.
<script>
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://xxx-xxxx-xx.herokuapp.com/api/foods/', true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.onload = function(){
console.log(xhr)
}
xhr.send(null);
</script>
It is your API in Heroku that needs to set the header, not the web client calling it.
Your browser is following the same origin policy by not allowing your page to request a resource in another domain. Your server can use CORS to let the browser know it is ok to make a request from another domain to this particular resource, but this information needs to come from your server.
The extension and Postman are not following the same origin policy like the browser is doing. The browser needs to follow this policy for your security.
How you set those headers really depends on how you implemented your endpoint in Heroku.
How do you get data from a REST API with JavaScript. I have several basic API's that I would like to get data from that don't require any authentication. All of the API's return the data I want back in JSON. For example https://www.codewars.com/api/v1/users/MrAutoIt. I thought this would be a very simple process using xmlhttprequest but it appears the same-origin policy is giving me problems.
I have tried following several tutorials but they don’t seem to work on cross domains or I don’t understand them. I tried to post links to the tutorials but I don't have a high enough reputation on here yet.
If you are trying to access a web service that is not on the same host:port as the webpage that is issuing the request, you will bump into the same origin policy. There are several things you can do, but all of them require the owner of the service to do things for you.
1) Since same origin policy does not impact scripts, allow the service to respond by JSONP instead of JSON; or
2) Send Access-Control-Allow-Origin header in the web service response that grants your webpage access
If you cannot get the service owner to grant you access, you can make a request serverside (e.g. from Node.js or PHP or Rails code) from a server that is under your control, then forward the data to your web page. However, depending on terms of service of the web service, you may be in breach, and you risk them banning your server.
In fact, it depends on what your server REST API supports regarding JSONP or CORS. You also need to understand how CORS works because there are two different cases:
Simple requests. We are in this case if we use HTTP methods GET, HEAD and POST. In the case of POST method, only content types with following values are supported: text/plain, application/x-www-form-urlencoded, multipart/form-data.
Preflighted requests. When you aren't in the case of simple requests, a first request (with HTTP method OPTIONS) is done to check what can be done in the context of cross-domain requests.
That said, you need to add something into your AJAX requests to enable CORS support on the server side. I think about headers like Origin, Access-Control-Request-Headers and Access-Control-Request-Method.
Most of JS libraries / frameworks like Angular support such approach.
With jQuery (see http://api.jquery.com/jquery.ajax/). There are some possible configurations at this level through crossDomain and xhrFields > withCredentials.
With Angular (see How to enable CORS in AngularJs):
angular
.module('mapManagerApp', [ (...) ]
.config(['$httpProvider', function($httpProvider) {
delete $httpProvider.defaults.headers.common['X-Requested-With'];
});
If you want to use low-level JS API for AJAX, you need to consider several things:
use XMLHttpRequest in Firefox 3.5+, Safari 4+ & Chrome and XDomainRequest object in IE8+
use xhr.withCredentials to true, if you want to use credentials with AJAX and CORS.
Here are some links that could help you:
Understanding and using CORS: https://templth.wordpress.com/2014/11/12/understanding-and-using-cors/
4 jQuery Cross-Domain AJAX Request methods: http://jquery-howto.blogspot.fr/2013/09/jquery-cross-domain-ajax-request.html#cors (see "1. CORS (Cross-Origin Resource Sharing)")
Unleash your AJAX requests with CORS: http://dev.housetrip.com/2014/04/17/unleash-your-ajax-requests-with-cors/
Using CORS for Cross Domain AJAX requests: http://techblog.constantcontact.com/software-development/using-cors-for-cross-domain-ajax-requests/
Cross origin resource sharing cors AJAX requests between jQuery and Node.js: http://www.bennadel.com/blog/2327-cross-origin-resource-sharing-cors-ajax-requests-between-jquery-and-node-js.htm
Hop it helps you,
Thierry
Here is how you get data.
var request = new XMLHttpRequest();
request.open('GET', 'https://www.codewars.com/api/v1/users/MrAutoIt', true);
request.onload = function() {
if (this.status >= 200 && this.status < 400) {
var resp = this.response; // Success! this is your data.
} else {
// We reached our target server, but it returned an error
}
};
request.onerror = function() {
// There was a connection error of some sort
};
request.send();
As far as running into same origin policy... You should be requesting from an origin you control, or you can try disabling Chrome's web security, or installing an extension such as Allow-Control-Allow-Origin * to force headers.
For a get method you could have something like this:
#section scripts{
<script type="text/javascript">
$(function()
{
$.getJSON('/api/contact', function(contactsJsonPayload)
{
$(contactsJsonPayload).each(function(i, item)
{
$('#contacts').append('<li>' + item.Name + '</li>');
});
});
});
</script>
}
In this tutorial check the topic: Exercise 3: Consume the Web API from an HTML Client
I have an AJAX call trying to execute the following CORS request to a Web Server (I am currently testing using only the latest version of Chrome):
var xhr = new XMLHttpRequest();
xhr.open("get", "http://www.web_server_url.com/query", true);
xhr.onload = function(){
};
xhr.send(null);
Meanwhile, I am still getting the following message:
XMLHttpRequest cannot load http://www.web_server_url.com/query. Origin http://localhost is not allowed by Access-Control-Allow-Origin.
Would someone know what I am missing?
The reason is exactly what it says in the error: The server at www.web_server_url.com is not allowing the localhost origin. It's up to the server to decide whether to allow the origin of the call. In this case, apparently it's not allowing it.
The way CORS works, the server replies to the request (or a "preflight" request) with headers either allowing or disallowing the origin on the basis of the information the browser sends it.
I'm making a JSON request to the Google Places API with:
function load(){
var req = new XMLHttpRequest();
req.open('GET', 'https://maps.googleapis.com/maps/api/place/details/json?reference=CnRhAAAARMUGgu2CeASdhvnbS40Y5y5wwMIqXKfL-n90TSsPvtkdYinuMQfA2gZTjFGuQ85AMx8HTV7axABS7XQgFKyzudGd7JgAeY0iFAUsG5Up64R5LviFkKMMAc2yhrZ1lTh9GqcYCOhfk2b7k8RPGAaPxBIQDRhqoKjsWjPJhSb_6u2tIxoUsGJsEjYhdRiKIo6eow2CQFw5W58&sensor=true&key=xxxxxxxxxxxxx', false);
req.send(null);
if(req.status == 200){
dump(req.responseText);
}
}
But Chrome is returning the error:
XMLHttpRequest cannot load https://maps.googleapis.com/maps/api/place/details/json?reference=CnRhAAAARMUGgu2CeASdhvnbS40Y5y5wwMIqXKfL-n90TSsPvtkdYinuMQfA2gZTjFGuQ85AMx8HTV7axABS7XQgFKyzudGd7JgAeY0iFAUsG5Up64R5LviFkKMMAc2yhrZ1lTh9GqcYCOhfk2b7k8RPGAaPxBIQDRhqoKjsWjPJhSb_6u2tIxoUsGJsEjYhdRiKIo6eow2CQFw5W58&sensor=true&key=xxxxxxxxxxxxxx.
Origin http://sandrayoon.com is not allowed by Access-Control-Allow-Origin.
Is there a way to prevent or circumvent cross-origin resource sharing? I am not very familiar with this security issue.
The only way to prevent this is to send proper Access-Control-Allow-Origin header from the server, which isn't under your control. So the basic answer is no. However you can consider using a server proxy, which would grab data from the server and send it to you from the same host as your client script was served.
Server should response with "Access-Control-Allow-Origin" header in order to let the browser to pass this response to javascript. You can also set "*" to allow any cross-domain requests.
Here is a good intro to the subject.