I'm on writing a little tracker in javascript. This tracker just gets the currently visited website with all needed informations. It also tracks ajax events. The counterpart is a java program which is hosted on the same machine as the webserver, but listening to a different port. My javascript program should not be able to send the data, because of the same origin policy (different port). The console in chrome tells me that:
XMLHttpRequest cannot load http://127.0.0.1:8082/posts. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8081' is therefore not allowed access.
What i don't get is, the data gets sent to the server! I double checked this on different machines (with different ip's). I just want to understand why. I did not write the send method on my own, thats why i don't really get it.
//sending data to server-tracker
function sendData(data)
{
console.log("Sending data: ");
console.log(data);
var xhr = window.XMLHttpRequest
? new window.XMLHttpRequest()
: window.ActiveXObject
? new ActiveXObject('Microsoft.XMLHTTP')
: null;
xhr.open('POST', "http://127.0.0.1:8082/posts", true);
xhr.send(data);
}
Thanks for helping.
The Same Origin Policy primarily stops JavaScript from reading data from other origins.
It has some features which prevent sending data to other origins under some circumstances. These can be summed up as "when the request couldn't have been constructed using an HTML form". These trigger a preflight request asking for permission to send the actual request.
Cross Origin Request Forgery which is a different problem and one best solved by using a Synchronizer Token (which is stored in HTML documents on the site (so it can only be sent by requests initiated from that site) and in the user's session (which is used to compare submitted ones).
Related
This question already has answers here:
Why does Ajax give me a cross origin error when I can make the request from PHP?
(3 answers)
Closed 7 years ago.
Under the same-origin policy, a web browser permits scripts contained in a first web page to access data in a second web page, but only if both web pages have the same origin.
But I did not get the essence of it. If I cannot make a cross domain request from my browser, I will make it through my PHP script. It will work fine. Isn't it?
So, instead of doing the following:
var xhr = new XMLHttpRequest();
var url = "https://www.google.com/finance/converter?a="+amount+'&from='+from+'&to='+to;
if(xhr) {
xhr.open('GET', url, true);
xhr.onload = function() {
// Handle
};
xhr.send();
}
which will result in :
XMLHttpRequest cannot load https://www.google.com/finance/converter?foo. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin abc.com is therefore not allowed access.
I could do via my own php script by sending a ajax request like:
$.ajax({
method: "GET",
url: "./bin/http/CimmClient.php",
dataType: 'html',
data:{
a: amount,
from: from,
to: to
}
})
.done(function(data, textStatus, jqXHR ){
// Handle
})
And this works perfectly fine. PHP only sends an HTTP request to another domain and then sends back the response to javascript.
So, what in principle was the difference? Why does the browser prevent sending cross domain HTTP request, when php/java/others would easily allow this?
These limitations are not implement to prevent YOU to use any kind of service, these are implemented in order to prevent a malicious code that you are not aware of to act ON YOUR BEHALF.
So, if YOU WANT to, you can obtain the data - e.g. using server side script, and that is OK. But if you load a malicious web page to your browser, or a web page that was infected by malware, its scripts are not able to act on your behalf and send requests to third party services.
It could be argued that there are legitimate use cases for such cross origin access, but the security on the Internet is a big thing and it is considered before comfort of developers.
For example, assume you have an online bank that uses cookies to store information on users' opened authenticated sessions. You log into a bank and check your accounts. You leave this tab open in your browser and you access a malicious website. That website sends Ajax to the bank asking for a list of transactions using a simple GET request. Your browser will invoke the GET request and send session cookies to the bank and the bank will reply with a sensitive information about your accounts. The malicious script then uploads the data to its server. Once the cross origin access is forbidden, this scenario is no longer possible.
I can make a GET request from PHP and get the correct response. This is the function I use:
PHP
function httpGet($url)
{
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch,CURLOPT_HEADER, false);
$output=curl_exec($ch);
curl_close($ch);
return $output;
}
A simple example:
$fakevalue='iamfake';
$url="http://fakeurl.com?fakeparameter=".$fakevalue;
$jsondata= httpGet($url);
$fake_array = json_decode($jsondata, true);
$weed_var=$fake_array['weeds']; // successfully obtained weed.
This function returns the response from the server.
Now I am trying the same HTTP GET request in AJAX, but I can't get the response.
Initially I thought the problem was with the JavaScript function that I use. Google provided with me lots of JavaScript functions for performing the HTTP GET request but they all had the same problem. The request returns an error instead of the data that I got when I used PHP.
JAVASCRIPT
var fakevalue = "iamfake";
var fake_data = {
fakeparameter: fakevalue
};
$.ajax({
url: "http://fakeurl.com",
data: fake_data,
type: "GET",
crossDomain: true,
dataType: "json",
success: function(a) {
$("#getcentre").html(a);
},
error: function() {
alert("Failed!");
}
});
Error from JavaScript
XMLHttpRequest cannot load http://fakeurl.com?fakeparameter=fakevalue. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.`
I know you are going to tell me to use CORS, but if it was because of the absence of 'Access-Control-Allow-Origin' header, then how did I get response for the same service in PHP?
With PHP (or anything else running on your server, or a standalone application (including those installed as a browser extension)), you are requesting data from Bob's server using your credentials (your cookies, your IP address, your everything else).
With Ajax, you are asking Alice's browser to request data from Bob's server using her credentials and then to make that data available to your JavaScript (which can then send it back to your server so you can see it yourself).
Bob might give different data to Alice then he would give to you. For example: Bob might be running Alice's eBanking system or company intranet.
Consequently, unless Bob's server tells Alice's browser that it is OK to make that data available to you (with CORS), the browser will prevent your JavaScript from accessing that data.
There are alternatives to CORS, but they involve either distributing the data using a file type that isn't designed to be a data format (JSONP) (which also requires Bob's server to cooperate) or having your server fetch the data from Bob and then make it available through a URL on your server (or some combination of the two like YQL does) (which means that you get the data Bob will give to you and not the data Bob will give to Alice).
Simple answer: PHP isn't affected by CORS. It is a restriction placed by the browser on client-side code, so that the accessed URL gets to allow or deny the request.
You are running into CORS, because you are doing an XMLHttpRequest request from your browser to a different domain than your page is on. The browser is blocking it as it usually allows a request in the same origin for security reasons. You need to do something different when you want to do a cross-domain request. Try this: http://www.html5rocks.com/en/tutorials/cors/
If you only want to launch a GET request, you might try using JSONP datatype="jsonp".
Examples: http://www.sitepoint.com/jsonp-examples/
I am trying to call the CTA API (http://www.transitchicago.com/developers/bustracker.aspx) from my local Wamp server. However, when doing the fetch via backbone collection I get:
XMLHttpRequest cannot load http://www.ctabustracker.com/bustime/api/v1/getroutes?key=xx. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.
collection:
define([
'models/route',
'core'
], function (Route) {
return Backbone.Collection.extend({
initialize: function () {},
model: Route,
//url: function () {
// return 'http://www.ctabustracker.com/bustime/api/v1/getroutes?key=xx';
//},
url: function () {
return '/apiproxy.php?method=getroutes';
},
});
});
I know this is a common issue but haven't found a concise answer yet.
How can I resolve this issue?
Update
Added the apiproxy but am getting this response:
Remote Address:127.0.0.1:80
Request URL:http://localhost/apiproxy.php?method=getroutes
Request Method:GET
Status Code:200 OK
Request Headersview parsed
GET /apiproxy.php?method=getroutes HTTP/1.1
console:
responseText: "$url = "http://www.ctabustracker.com/bustime/api/v1/{$_GET['method']}? key=xx";
↵echo file_get_contents($url);
SyntaxError {stack: (...), message: "Unexpected token $"}
message: "Unexpected token $"
stack: (...)
You can solve this problem, but it's not a simple case of "add this line to your JavaScript and everything will be fine."
You're running up against the same-origin security policy built into every web browser. 'Origin' basically means 'the same site'; my JavaScript on example.com can access whatever it likes on example.com, but it's not allowed to read anything from demonstration.com, example.net, or api.example.com. That's got a different origin. Here's a table of what counts as the same origin.
Without it, I could write a web page that steals all your gmail and private Facebook photos. My malicious JavaScript would make web requests to gmail.com and facebook.com, find the links to your emails & photos, load that data too, and then send it off to my own server.
Obviously, some web pages are designed to be used by other people. APIs, for instance, generally want to allow access to their data so people can build web apps. The people building those APIs can serve their content with Access-Control- headers that tell browsers it's OK to allow requests from other sites. This is called CORS - Cross-Origin Resource Sharing. The reason you get that error message is because the ctabustracker.com developers haven't added any CORS headers. Thus, you can't access their API from your JavaScript.
So what's the solution? you have two options:
Email the ctabustracker.com admins and ask them to add CORS headers to allow access from other domains. This is the least work for you, but you're at the mercy of the knowledge, infrastructure, & promptness of their development team.
Write your own proxy server.
The same-origin policy is only standing in your way in your JavaScript. You can do whatever you like on the server; at its simplest, you could create an apiproxy.php along these lines:
$allExceptMethod = $_GET; // PHP arrays are copy-by-value
unset($allExceptMethod['method']);
$url = "http://www.ctabustracker.com/bustime/api/v1/{$_GET['method']}?key=xx&" . http_build_query($allExceptMethod);
echo file_get_contents($url);
And then access it from your JavaScript as /apiproxy.php?method=getroutes, and pass extra parameters in via a standard query string (for instance, /apiproxy.php?method=test&foo=bar&cat=dog results in a request to http://www.ctabustracker.com/bustime/api/v1/test?key=xx&foo=bar&cat=dog). Now your JavaScript is making a request to your own server, so you won't have any problems with the same-origin policy.
You can, of course, make your proxy as smart as you like. It could cache responses, convert your XML to JSON, pre-fetch the results for likely next requests, or 100 other things that may be useful for your app.
As an example case let's take this url: http://api.duckduckgo.com/?q=computer&format=json (CORS not enabled on this server!)
We can access the contents from this URL from any popular browser as a normal URL, browser has no issues opening this URL nor the server returns any error.
A server-side language like PHP/RoR can fetch the contents from this URL without adding any additional headers or special server settings. I used following PHP code and it simply worked.
$url='http://api.duckduckgo.com/?q=computer&format=json';
$json = file_get_contents($url);
echo $json;
I just started working in javascript framework, AngularJS. I used following code...
delete $http.defaults.headers.common['X-Requested-With'];
var url="http://api.duckduckgo.com/?q=computer&format=json";
$http.get(url)
.success(function(data) {
$scope.results=data;
})
With above AngularJS code, I received following error:
XMLHttpRequest cannot load http://api.duckduckgo.com/?q=computer&format=json. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63342' is therefore not allowed access.
AngularJS uses JQuery so I tried the same in JQuery with following code:
var url="http://api.duckduckgo.com/?q=computer&format=json";
$.getJSON(url , function( data ) {
console.log(data);
});
This also produced the same error as did AngularJS code.
Then my further research brought me to the point that it's actually not specific to JQuery and AngularJS. Both of these inherit this issue from Javascript!
Here is an excellent resource with explanation of what CORS is and how to handle with it: http://enable-cors.org/index.html.
And also W3C has it official CORS specification: http://www.w3.org/TR/cors/
So my question is not what CORS is. My question is
My understanding is that whether it is a web browser or it is PHP/RoR or it is Javascript frameworks, all make requests to a URL via the same http or https, right? Certainly, yes. Then why http has to be more secure when requests come from javascript? How does http and server know that request is coming from javascript?
When a web browser can open a URL and PHP/RoR (or any server-side language) can access that URL without any extra settings/headers, why can't AngularJS, JQuery (or in a single word javascript) access that URL unless the server has set Access-Control-Allow-Origin header for requesting root?
What's that special feature (that PHP/RoR have and) that is missing in Javascript so that it can't access the same URL in the same browsers that can open that URL without any issue from their address bars?
Just to mention that I am basically an iOS developer and recently started to learn web development, specially AngularJS. So I am curious about what's all this going on and why!
It's disabled from javascript for security reasons. Here's one scenario:
Assume Facebook has a "post message on timeline" api that requires the user to be authenticated.
You are logged into Facebook when you visit badsite.com.
badsite.com uses javascript to call the Facebook api. Since the browser is making a valid request to Facebook, your authentication cookie is sent, and Facebook accepts the message and posts badsite's ad on your timeline.
This isn't an issue from a server, because badsite.com's server doesn't have access to your Facebook authentication cookie and it can't forge a valid request on your behalf.
You remember that all javascript request is handled by browser. So browser detect cross-origin request is easy.
Request from javascript has no difference with PHP/RoR, it is only rejected by browser.
Server code can accept cross-origin javascript request by header "Access-Control-Allow-Origin" because before reject javascript request, browser will send a request "OPTIONS" to server to ask header "Access-Control-Allow-Origin" on response. If value is match with current origin, browser will accept javascript request and send to server.
All browser are implement this policy Same Origin Policy
Please read http://en.wikipedia.org/wiki/Cross-site_scripting, you will get the reason why its prohibited for JavaScript.
I'm having troubles with collecting json values from a URL in my application. When I try to get them a error log is displayed in the console saying that origin is not allowed by access-control-allow-origin.
I researched a bit and found out that response headers have to be set to Access-Control-Allow-Origin: *
How can I do that using pure javascript? No jquery or any other library.
This is my current code:
<script type="text/javascript">
var xmlHttp = null;
xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", "http://example.com/id=69", false );
xmlHttp.send( null );
console.log("JSON values from URL: ");
console.log(xmlHttp.responseText);
</script>
I researched a bit and found out that response headers have to be set to Access-Control-Allow-Origin: *
How can I do that using pure javascript? No jquery or any other library.
You can't, not unless your server is running JavaScript (NodeJS, etc.).
The server has to allow access to the resource from the origin of your document. The way it works is:
The browser asks permission to access the resource (this is called a "preflight" request), telling the server what resource it wants access to, etc.
The server replies with the appropriate headers telling the browser whether access will be allowed.
The browser sends the actual request.
The server responds to it (again including the relevant headers).
I believe there are situations where the pre-flight isn't necessary. All of that is handled for you by the XMLHttpRequest object.
Details in the Cross-Origin Resource Sharing specification.
You cannot do this on client side, your server must send these headers.