CORS redirect works unexpectedly - javascript

According to CORS specification (7.1.7 - Redirect Steps (for Simple Cross-Origin Request)):
If the request URL origin is not same origin with the original URL origin, set source origin to a globally unique identifier (becomes "null" when transmitted).
I have a scenario where javascript from a.blah.com makes a CORS request (i.e. Origin request header present) by sending browser to b.blah.com, which responds with a 302 and location = c.blah.com. If I am reading the spec correctly, this should result in the request to c.blah.com containing Origin header = "null". Instead, the Origin header is not present and thus the request to c.blah.com is not considered a CORS request.
The above behavior was experienced in Chrome 54. I have not confirmed the exact request contents in other browsers, but I have checked that my particular application flow works in Chrome 54, Firefox 37, and IE 11 browsers, which implies they never see Origin header set to "null" (my services will fail requests loudly if the receive an Origin = "null").
This all worries me because while my application is working, it actually shouldn't be, and I don't want to just ignore this fact. Am I misunderstanding the spec? Are there any caveats to the spec behavior that I've missed?
All traffic is HTTPS, not returning * (wildcard) in CORS response header, setting with-credentials flags/headers as appropriate, no proxies in use, all actors on separate machines so should not be a localhost gotcha...
Thanks.

In my original configuration, the request to b.blah.com was a form posted by js (not xhr). After some digging around, it seems that since the request was triggered by js, that warranted an Origin header on the request to b.blah.com, but the resulting redirect to c.blah.com was handled by the browser without any script/xhr intervention, so the redirect was not decorated with an Origin header.
I set up a test where the request to b.blah.com was xhr, and that did cause an Origin = "null" on the redirect to c.blah.com.
I suppose I need to better research the nuances of when same-origin policy is enforced.
Thanks.

Related

How does stackoverflow set origin: null in http requests [duplicate]

As you can see from this Bugzilla thread (and also), Firefox does not always send an Origin header in POST requests. The RFC states that it should not be sent in certain undefined "privacy-sensitive" contexts. Mozilla defines those contexts here.
I'd like to know whether these are the only situations in which Firefox will not send the Origin header. As far as I can tell, it also will not send it in cross-origin POST requests (though Chrome and Internet Explorer will), but I can't confirm that in the documentation. Is it enumerated somewhere that I'm missing?
As far as what the relevant specs actually require, the answer has a couple parts:
When browsers must internally set an origin to a value that’ll get serialized as null
When browsers must send the Origin header
Here are the details:
When browsers must set origin to a value that’ll get serialized as null
The HTML spec uses the term opaque origin and defines it as an “internal value”:
with no serialization it can be recreated from (it is serialized as "null" per ASCII serialization of an origin), for which the only meaningful operation is testing for equality
In other words everywhere the HTML spec says opaque origin, you can translate that to null.
The HTML spec requires browsers to set an opaque origin or unique origin in these cases:
Cross-origin images (including cross-origin img elements)
Cross-origin media data (including cross-origin video and audio elements)
Any document generated from a data: URL
Any iframe with a sandbox attribute that doesn’t contain the value allow-same-origin
Any document programmatically created using createDocument(), etc.
Any document that does not have a creator browsing context
Responses that are network errors
The Should navigation response to navigation request of type from source in target be blocked by Content Security Policy? algorithm returns Blocked when executed on a navigate response
The Fetch spec requires browsers to set the origin to a “globally unique identifier” (which basically means the same thing as “opaque origin” which basically means null…) in one case:
Redirects across origins
The URL spec requires browsers to set an opaque origin in the following cases:
For blob: URLs
For file: URLs
For any other URLs whose scheme is not one of http, https, ftp, ws, wss, or gopher.
But note that just because the browser has internally set an opaque origin—essentially null—that doesn’t necessarily mean the browser will send an Origin header. So see the next part of this answer for details about when browsers must send the Origin header.
When browsers must send the Origin header
Browsers send the Origin header for cross-origin requests initiated by a fetch() or XHR call, or by an ajax method from a JavaScript library (axios, jQuery, etc.) — but not for normal page navigations (that is, when you open a web page directly in a browser), and not (normally) for resources embedded in a web page (for example, not for CSS stylesheets, scripts, or images).
But that description is a simplification. There are cases other than cross-origin XHR/fetch/ajax calls when browsers send the Origin header, and cases when browsers send the Origin header for embedded resources. So what follows below is the longer answer.
In terms of the spec requirements: The spec requires the Origin header to be sent only for any request which the Fetch spec defines as a CORS request:
A CORS request is an HTTP request that includes an Origin header. It cannot be reliably identified as participating in the CORS protocol as the Origin header is also included for all requests whose method is neither GET nor HEAD.
So, what the spec means there is: The Origin header is sent in all cross-origin requests, but it’s also always sent for all POST, PUT, PATCH, and DELETE requests — even for same-origin POST, PUT, PATCH, and DELETE requests (which by definition in Fetch are actually “CORS requests” — even though they’re same-origin).*
The other cases when browsers must send the Origin header are any cases where a request is made with the “CORS flag” set — which, as far as HTTP(S) requests, is except when the request mode is navigate, websocket, same-origin, or no-cors.
XHR always sets the mode to cors. But with the Fetch API, those request modes are the ones you can set with the mode field of the init-object argument to the fetch(…) method:
fetch("http://example.com", { mode: 'no-cors' }) // no Origin will be sent
Font requests always have the mode set to cors and so always have the Origin header.
And for any element with a crossorigin attribute (aka “CORS setting attribute”), the HTML spec requires browsers to set the request mode to cors (and to send the Origin header).
Otherwise, for embedded resources — any elements having attributes with URLs that initiate requests (<script src>, stylesheets, images, media elements) — the mode for the requests defaults to no-cors; and since those requests are GET requests, that means, per-spec, browsers send no Origin header for them.
When HTML form elements initiate POST requests, the mode for those POSTs also defaults to no-cors — in the same way that embedded resources have their mode defaulted to no-cors. However, unlike the no-cors mode GET requests for embedded resources, browsers do send the Origin header for those no-cors mode POSTs initiated from HTML form elements.
The reason for that is, as mentioned earlier in this answer, browsers always send the Origin header in all POST, PUT, PATCH, and DELETE requests.
Also, for completeness here and to be clear: For navigations, browsers send no Origin header. That is, if a user navigates directly to a resource — by pasting a URL into a browser address bar, or by following a link from another web document — then browsers send no Origin header.
* The algorithm in the Fetch spec that requires browsers to send the Origin header for all CORS requests is this:
To append a request Origin header, given a request request, run these steps:
1. Let serializedOrigin be the result of byte-serializing a request origin with request.
2. If request’s response tainting is "cors" or request’s mode is "websocket", then
    append Origin/serializedOrigin to request’s header list.
3. Otherwise, if request’s method is neither GET nor HEAD,
    then: [also send the Origin header in that case too]
Step 2 there is what requires the Origin header to be sent in all cross-origin requests — because all cross-origin requests have their response tainting set to "cors".
But step 3 there requires the Origin header to also be sent for same-origin POST, PUT, PATCH, and DELETE requests (which by definition in Fetch are actually “CORS requests” — even though they’re same-origin).
The above describes how the Fetch spec currently defines the requirements, due to a change that was made to the spec on 2016-12-09. Up until then the requirements were different:
  •  previously no Origin was sent for a same-origin POST
  •  previously no Origin was sent for cross-origin POST from a <form> (without CORS)
So the Firefox behavior the question describes is what the spec previously required, not what it currently requires.
For me this was happening on a super-standard form POST to a relative URL on localhost, and seems to have been triggered by having
<meta name="referrer" content="no-referrer">
in the <head>.
Changing it to
<meta name="referrer" content="same-origin">
seemed to make Firefox happier.

Permanent Solution for "No 'Access-Control-Allow-Origin' header is present on the requested resource"

I have seen this problem quite a few times and it pops up time and again. This is a CORS(i.e. Cross origin request issue).The exact error I got this time is as follows:
XMLHttpRequest cannot load
https://myURL/myappdomain.subdomain.qual1/$count. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 401.
Following are the possible solutions I have worked out in past. But they dont always work. They are URL specific solutions:
1) Having CORS plugin on chrome installed
2) Disabling web security from command line "--disable-web-security"
3) using 'jsonp' as format instead of 'json'
4) toggling cross-origin to "true" or "false".
Questions I need answer for
1) Why do we get this error? Is it something that the Server is imposing on the client pages?
2) What is the safest way to solve this? i.e. The method in which there is not security vulnerability and a reliable method.
3) Why cors is never an issue for API calls made from within nodeJS code?

Why does the browser allow xorigin POST but not PUT?

Consider the very simple example of using XMLHttpRequest.
The following posts properly ( you can see it in the network tab or by directing your browser to http://requestb.in/yckncpyc) although it prints a warning to the console
XMLHttpRequest cannot load http://requestb.in/yckncpyc. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'null' is therefore not allowed access.
const method = "POST"
const req = new XMLHttpRequest()
req.open(method, 'http://requestb.in/yckncpyc')
req.send("foobar")
console.log("sent")
req.addEventListener('load', function() { console.log(req.status, req.response) })
Sure. I get that. What I don't get is why merely changing the verb used to a PUT results in something completely different. The request sent is an OPTIONS preflight request and prints
XMLHttpRequest cannot load http://requestb.in/yckncpyc. Response to
preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'null' is therefore not allowed access.
const method = "PUT"
const req = new XMLHttpRequest()
req.open(method, 'http://requestb.in/yckncpyc')
req.send("foobar")
console.log("sent")
req.addEventListener('load', function() { console.log(req.status, req.response) })
Why does the browser* treat these differently? It seems like something that would be done for security but that really makes no sense since an attacker can always use a POST instead of a PUT.
So what is the logic here?
Tried this in Chrome 52, Safari 9.1.2
GET, HEAD, and POST requests (with a couple other restrictions) can be made cross-origin with no additional communication. The responses cannot be examined, but the requests are allowed.
Anything else requires a preflight request to check the headers from the target site to see whether the request would be allowed.
The reason for such a setup is that GET, HEAD, and POST were historically allowed from browsers as a natural part of HTML semantics. Tags for scripts and CSS and images do GET requests, and forms do POSTs. When the CORS stuff was introduced, therefore, those were allowed under the assumption that sites were no more vulnerable to simple requests like that in an XHR world then they were in the simpler non-XHR world.
So simple requests are allowed, and the browser looks at the response headers to decide whether the requesting code in the cross-origin page should be allowed to see the response content. For other requests, the browser first sends an OPTIONS request to check the CORS response headers. Only if that looks OK (that is, if the response headers contain the appropriate "yes that's OK" headers) will the XHR be allowed to proceed.

No 'Access-Control-Allow-Origin' header is present on the requested resource on AJAX request

I'm using JQuery:
$('#myDiv').load('myApp/url',function(){ });
and it's giving No 'Access-Control-Allow-Origin' header is present on the requested resource By chrome, and firefox so far , any straight forward answer on how to fix this . I don't have control over server to make any configurations and I'm using PHP
This is a CORS issue (Cross Origin Resource Sharing), you are trying to request content via ajax from two different domains. Unless the domain from where you want to grab the data has properly set the CORS headers, browsers will cancel the request right away.
This occurs due to the communication between two different domains. The domain that will server your data, should have some headers set, this headers act as permissions, they tell which domains are allowed to ask for data from it, and which verbs/methods are allowed.
You can read more about this here and here
No, there won't be a straight forward answer to this because it will depend entirely on your system/server setup, and what you have access to. Here's what you need to know.
In the beginning -- AJAX requests had a very strict "same origin" policy. This meant if you made an ajax request FROM a website with the domain example.com, you could only make a request to a URL that was on example.com.
In more recent years browsers have loosened up on this. If the server that you're making a request to has an Access-Control-Allow-Origin header, and that header includes the URL/domain of the server you're making the request from, then the request will be allowed. Similar question/answer here.
So, how you set this header depends on the server you're making a request to. If you have control over this server, start your Googling there.
If you don't have control over this server, you need to make a request to php page on your server, and this PHP page should make a curl request to the server that had the information you don't. A curl request, happening outside the browser, isn't subject to the same cross domain issues.
The easy way is to do this by hand:
var script = document.createElement('script');
script.src = uri;
script.id = 'scriptid';
document.head.appendChild(script);
It may be some browser compatibility issues, but you get the power of CORS with no 'Access-Control-Allow-Origin' error

SEC7118: XMLHttpRequest CORS - IE Console message

I am using CORS POST request with everything taken care as given #http://www.html5rocks.com/en/tutorials/cors/
Server sets Response header to:
'Access-Control-Allow-Origin':'*' and I can see this header value in IE developer tool.
But on IE10 browser I see console message as "SEC7118: XMLHttpRequest for http:// required Cross Origin Resource Sharing (CORS).
When I check on Microsoft site it has below given explanation.
http://msdn.microsoft.com/en-us/ie/dn423949(v=vs.94).aspx
SEC7118
Description:
"XMLHttpRequest for [URL] required Cross Origin Resource Sharing (CORS). "
An XMLHttpRequest was made to a domain that was different than your page's domain. This requires the server to return an "Access-Control-Allow-Origin" header in its response headers, but one was not returned.
Suggested Fix:
The server must support CORS requests and return an appropriate "Access-Control-Allow-Origin" header with the resource. See CORS for XHR in IE10 for more info about CORS in response headers.
Questions:
I want to know if this console message is an ERROR ??
Will this cause any failures ??
Why do I get this message even after setting response header 'Access-Control-Allow-Origin' value to '*'??
Does 'Access-Control-Allow-Origin' value has to be origin name for
IE10 to work? I know * is not a very good option, But does IE
requires exact origin name ??
I kept URL's and cookie details hidden from these images.
From MSDN:
Security error codes are in the form SEC7xxx [In IE]
Pertaining to SEC7118:
An XMLHttpRequest was made to a domain that was different than your page's domain. This requires the server to return an "Access-Control-Allow-Origin" header in its response headers, but one was not returned.
Note This error code was removed in IE11 on Windows 10. It remains in IE11 for Windows 8.1 and Windows 7.
So it is technically viewed as an error from IE's perspective, but certainly isn't one (hence why it is going away). Access-Control-Allow-Origin is set on a resource, but isn't necessarily sent back with the request. If a specified resource DOESN'T have Access-Control-Allow-Origin:* (or a domain), the resource would not be accessible and the server would likely return a 503 or 404 and you would see a true error message in the console similar to the below:
XMLHttpRequest cannot load http://example.com/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://blog.example.com' is therefore not allowed access.
I encountered SEC7118 when CORS was set up correctly. I verified that the requests were completing with status 200 using the network debugger. So, you can disregard this message if your application is otherwise functioning properly.
I have seen this error in IE11:
SEC7118: XMLHttpRequest for http:// required Cross Origin Resource Sharing (CORS)
Adding the following to my .htaccess fixed it:
<IfModule mod_setenvif.c>
<IfModule mod_headers.c>
<FilesMatch "\.(cur|gif|ico|jpe?g|png|svgz?|webp)$">
SetEnvIf Origin ":" IS_CORS
Header set Access-Control-Allow-Origin "*" env=IS_CORS
</FilesMatch>
</IfModule>
</IfModule>
Reference:
https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image
I had this same issue. It has to do with Internet Explorer's handing of third party cookies. You can fix this issue by going into Tools>Internet Options then selecting the Privacy tab. If you change the setting to "Accept All Cookies" you will no longer see that message.
The safer way to do this would be to click on the "Sites" button and allow cookies from your site's url.

Categories

Resources