CORS and Origin header? - javascript

When we need to invoke an Ajax request we do :
if(typeof XMLHttpRequest !== 'undefined') xhr = new XMLHttpRequest();
else
{
var versions = ["Microsoft.XmlHttp",
"MSXML2.XmlHttp",
"MSXML2.XmlHttp.3.0",
"MSXML2.XmlHttp.4.0",
"MSXML2.XmlHttp.5.0"
];
I already know that using XMLHttpRequest-2 ,we can make a cross origin request AND that the ORIGIN header is added.
Question:
When does this header added ?
Is it added when a browser (that support CORS) is performing a request ? ( cross domain or non-cross-domain?)
Or is it added automatically when the browser "sees" that the request target origin is different from the current origin...
I mean : what the He** does the bold line mean ?
Cross-origin HTTP requests have an Origin header. This header
provides the server with the request’s origin. This header is
protected by the browser and cannot be changed from application code.
In essence, it is the network equivalent of the origin property found
on message events used in Cross Document Messaging. The origin header
differs from the older referer [sic] header in that the referer is a
complete URL including the path. Because the path may contain
sensitive information, the referer is sometimes not sent by browsers
attempting to protect user privacy. However, the browser will always
send the required Origin headers when necessary.

The Origin header
When this header is added ?
During the header's stage, before the document's body is sent (after open, before send).
Is it added when a browser (that support CORS) is doing a request ? ( cross domain or non-cross-domain?)
It is added when the origin doesn't match the page from which the XMLHttpRequest is created, but may also be sent in a same-origin request.
Or does it added automatically when the browser "sees" that the request target origin is different from the current origin...
Yes.
However, the browser will always send the required Origin headers when necessary.
This is part of the XMLHttpRequest spec; if you're making a cross-domain request, in the request headers an extra header is sent. This header is e.g. Origin: http://www.stackoverflow.com and is appended by a standards-following browser without user interaction.
You can read more on the specification in MozillaWiki's Security section, WHATWG and html5.org. It is implemented by (that I know of) FireFox and Google Chrome. I don't believe it is part of W3C yet. Further do not assume the origin header is true, as it can be set manually by modified borwsers or other software.

The origin header is added automatically (generally) when you do a cross domain request.
To test it, I opened the console on this page and made two different requests: one for another domain and one for '/' and just the first got the origin header added.
BTW, I'm using JQuery for it and I'd really advise you to use it too in order to have the same behavior cross-browser.
For complementary info on the subject, check this:
The first thing to note is that a valid CORS request always contains
an Origin header. This Origin header is added by the browser, and can
not be controlled by the user. The value of this header is the scheme
(e.g. http), domain (e.g. bob.com) and port (included only if it is
not a default port, e.g. 81) from which the request originates; for
example: http://api.alice.com.
The presence of the Origin header does not necessarily mean that the
request is a cross-origin request. While all cross-origin requests
will contain an Origin header, some same-origin requests might have
one as well. For example, Firefox doesn't include an Origin header on
same-origin requests. But Chrome and Safari include an Origin header
on same-origin POST/PUT/DELETE requests (same-origin GET requests will
not have an Origin header).
Source

Related

How to get URL, that browser uses for CSP

I'm creating a script, that embed iframe with my site to client's site, but I want to limit access to this feature.
I added 2 headers to the server responses
Content-Security-Policy: "frame-ancestors: example.com"
X-Frame-Options: ALLOW-FROM example.com
It works, but X-Frame-Options doesn't support multiple domains, so I added a GET-param to the iframe URLs, that contain frame ancestor URL
And when http://example.net requests mysite.com/embed/?from=http://example.net I check the whitelist and send this domain in headers
My problem is obtaining a real page origin, that browser uses to compare with the headers.
I tried location.origin and document.referrer but both return wrong values when I request iframe from iframe.
For example http://jsbin.com. I can't find way to obtain real URL in sandboxed code, it's always http://null.jsbin.com. But for Content-Security-Policy a browser uses http://jsbin.com/

Why does No 'Access-Control-Allow-Origin' is not enforced when I call third party services, but it is when I call my own server?

I'm building a RESTful service on a JAX-RS server and some clients that will be attached to it.
The hour came to start testing the endpoints on the clients and I tried first on JavaScript since until now, it has been very easy for me to make requests to third party resources with this code:
function httpGet(theUrl){
var xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", theUrl, false );
xmlHttp.send( null );
return xmlHttp.responseText;
}
I know I shouldn't do synchronous requests but that's off topic.
On Firefox, the error I get is:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://someurl.com/someresource/. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
The requests don't work both on my local server and on the deployment server.
I've found that most solutions to this problem have to do something with setting a header Access-Control-Allow-Origin: *. I've tried this and it hasn't worked for me.
At first I thought it was a problem with my server configuration, but now I think it's the browser that is not letting me execute the request because of the Same Origin Policy. Is this correct? If it's correct, why does the exact same code as above, with no Access-Control-Allow-Headers: *, works for third party services (Google, Facebook, etc.)?
Is there a whitelist of sites that are always allowed to break the Same Origin Policy?
If the answer to the last question is no, then they must have some specific configutation on their server side code to allow Cross Origin communications to happen. What could this configuration be?
At first I thought it was a problem with my server configuration
It is.
but now I think it's the browser that is not letting me execute the request because of the Same Origin Policy.
That's true. The browser is disallowing the request per the SOP because your server isn't configured to allow cross-origin requests.
It's much more than just passing back a single header. Full details in the spec, but basically it comes down to:
Responding to OPTIONS requests, not just GET, POST, and so on.
Responding with all of the necessary headers.
Responding with the correct values for those headers.
The headers you'll have to send back are at least:
Access-Control-Allow-Origin
Access-Control-Allow-Methods
Access-Control-Allow-Headers
and you may also need Access-Control-Allow-Credentials. The values you need to supply for these are usually derived from the headers with similar (but slightly different) names that accompany the request.
You must supply the headers both in response to the OPTIONS call (if there is one), and also the subsequent GET or POST etc. call.
If it's correct, why does the exact same code as above, with no Access-Control-Allow-Headers: *, works for third party services (Google, Facebook, etc.)?
The browser fills in the request headers automatically; what's different is the server responding to the request.
Is there a whitelist of sites that are always allowed to break the Same Origin Policy?
No, of course not.
If the answer to the last question is no, then they must have some specific configutation on their server side code to allow Cross Origin communications to happen. What could this configuration be?
The above.
Here's some pseudocode for the server side granting access via CORS (it's written in JavaScript, since I know you're familiar with JavaScript, but it is pseudocode, and you need to do this on your server):
var origin, method, headers;
origin = getRequestHeader("Origin");
if (origin /* and you want to grant access to it */) {
addResponseHeader("Access-Control-Allow-Origin", origin);
method = getRequestHeader("Access-Control-Request-Method");
if (method) {
// Note the request header is singular, but the response header is plural
addResponseHeader("Access-Control-Allow-Methods", method);
}
headers = getRequestHeader("Access-Control-Request-Headers");
if (headers) {
addResponseHeader("Access-Control-Allow-Headers", headers);
}
if (/* You want to allow the origin to provide credentials and cookies*/) {
addResponseHeader("Access-Control-Allow-Credentials", "true");
}
}
At first I thought it was a problem with my server configuration, but now I think it's the browser that is not letting me execute the request because of the Same Origin Policy. Is this correct?
By default, the browser will enforce the Same Origin Policy and block your JavaScript from accessing the data.
The configuration of the server you are making the request to can set CORS headers (including Access-Control-Allow-Origin and Access-Control-Allow-Headers) to tell the browser not to enforce the Same Origin Policy for that request.
Is there a whitelist of sites that are always allowed to break the Same Origin Policy?
No
If the answer to the last question is no, then they must have some specific configutation on their server side code to allow Cross Origin communications to happen. What could this configuration be?
The configuration sets the response headers that are described in the error message you quoted.

Cross-domain XMLHttpRequest, Access-Control-Allow-Origin header and $_SERVER['HTTP_ORIGIN']

I need a script to deliver information to requesting-pages hosted on different domains, through XMLHttpRequest. There are many questions and answers on the subject, but none of the ones I found fully answered my questions.
Searching on the net brought me to find out that I must allow these domains through headers like
header("Access-Control-Allow-Origin: *"); or
header("Access-Control-Allow-Origin: http://example.com");
As I need more than one external domain, but still I find * much too open, further researches brought me on solutions relying on server-side comparison of $_SERVER['HTTP_ORIGIN'] with authorized values. (on StackOverflow: Access-Control-Allow-Origin Multiple Origin Domains? for instance)
BUT I found no mention of $_SERVER['HTTP_ORIGIN'] in php manuel (http://php.net/manual/fr/reserved.variables.server.php) and my tests revealed that this entry isn't always set.
So my questions are:
- when is the $_SERVER['HTTP_ORIGIN'] superglobal set?
- is it reliable globally?... or client browser dependant?
It seems (but just empirically, from my tests / Firefox 34.0.5 & ios Safari) that it is only set when 'needed', ie when request actually comes from another domain.
See short code extract hereunder to help understand the need
- no header sent if $_SERVER['HTTP_ORIGIN'] not defined
(assuming it's effectively not a cross domain call, there shouldn't be any problem),
- send "allow" header if defined and belonging to an array of accepted domains.
if(isset($_SERVER['HTTP_ORIGIN'])) {// in case of cross domain ajax call
$http_origin = $_SERVER['HTTP_ORIGIN'];
if(in_array($http_origin, $ajaxAllowedDomains))
{ header("Access-Control-Allow-Origin: $http_origin"); }
}
when is the $_SERVER['HTTP_ORIGIN'] superglobal set?
When the HTTP request includes an Origin header. Browsers will set one when making a cross-domain request with XMLHttpRequest.
is it reliable globally?
It is in situations where you might want to set CORS response headers.

Does Cross-Origin Resource Sharing(CORS) differentiate between HTTP AND HTTPS?

I have two sites : https//:www.domain-only-uses-https.com and www.domain-uses-both-http-and-https.com
Now I am making 2 ajax GET requests in the page of the former to the later, one is
https://www.domain-uses-both-http-and-https.com/some-path (using the HTTPS scheme)
and the other one is
http://www.domain-uses-both-http-and-https.com/some-other-path (using the HTTP scheme)
And I DID set the "https//:www.domain-only-uses-https.com" as the value of "Access-Control-Allow-Origin:" header in the server "www.domain-uses-both-http-and-https.com ".
But now it seems that only request 1 is allowed by Chrome ,but request 2 is forbidden.
So my question is : does the "Access-Control-Allow-Origin" header differentiate between HTTP AND HTTPS?
Hope I've made myself clear..
Yes, HTTP and HTTPS origins are different.
An origin is a combination of hostname, port, and scheme.
http://foo.example.com:8080/
^^^^ ^^^^^^^^^^^^^^^ ^^^^
|| || ||
scheme hostname port
If not all of these fields match between two resources, then the resources are from different origins. Thus, you must expressly specify whether the resource is accessible from the origin with an HTTP scheme or the origin with an HTTPS scheme.
Some browsers only allow the Access-Control-Allow-Origin header to contain exactly one origin (or *) sent with each response; however, your server can detect the request's Origin header and send the same origin in the CORS response.

Chrome adding Origin header to same-origin request

We're POSTing an AJAX request to a server running locally, i.e.
xhr.open("POST", "http://localhost:9000/context/request");
xhr.addHeader(someCustomHeaders);
xhr.send(someData);
The page that this javascript is being executed is also being served from localhost:9000, i.e. this totally looks like a same-origin request.
However, for some reason, Google Chrome always sets an Origin header in the resulting request, causing our server to block the request based on the false assumption that it's CORS request.
This does not happen in Firefox.
Also, neither Firefox nor Chrome are sending an OPTIONS preflight request, which is confusing; why set an Origin header without first preflighting to make sure the the Origin and the Custom headers are allowed by the server?
Does anyone know what is going on in this case? Are we misunderstanding the CORS spec?
Chrome and Safari include an Origin header on same-origin POST/PUT/DELETE requests (same-origin GET requests will not have an Origin header). Firefox doesn't include an Origin header on same-origin requests. Browsers don't expect CORS response headers on same-origin requests, so the response to a same-origin request is sent to the user, regardless of whether it has CORS headers or not.
I would recommend checking the Host header, and if it matches the domain in the Origin header, don't treat the request as CORS. The headers look something like this:
Host: example.com
Origin: http://example.com
Note that Origin will have the scheme (http/https), domain and port, while Host will only have the domain and port.
According to RFC 6454 - The Web Origin Concept - the presence of Origin is actually legal for any HTTP request, including same-origin requests:
https://www.rfc-editor.org/rfc/rfc6454#section-7.3
"The user agent MAY include an Origin header field in any HTTP
request."

Categories