Access-Control-Allow-Origin is not matched when server responds 304 - web

I have an API server api.example.com and two websites a.example.com, b.example.com. To enable CORS, I set up CORS headers for them.
An XHR request from a.example.com will get the response headers from api.example.com
access-control-allow-credentials: true
access-control-allow-methods: GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS
access-control-allow-origin: https://a.example.com
access-control-max-age: 0
vary: origin
Similarly, an XHR request from b.example.com will get the response headers from api.example.com
access-control-allow-credentials: true
access-control-allow-methods: GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS
access-control-allow-origin: https://b.example.com
access-control-max-age: 0
vary: origin
When I fetches resource GET api.example.com/articles/1 in a.example.com and then go to b.example.com do the same action to fetch the resource. The browser will use if-none-match headers to get the resource and receives a 304 response code from server. Then it complains that Access-Control-Allow-Origin header has a value https://a.example.com that is not equal to the supplied origin. Origin https://b.example.com is therefore not allowed access.
I think browser uses its cache when 304 is responded and find out Access-Control-Allow-Origin is cached as a.example.com's resource therefore refuse to fulfill the request.
How can I mitigate the issue here? Any thought?

Requests are cached, including its content and headers.
When you access a the first time. The response is generated and saved in the cache.
When you access b afterwards. The 304 response comes with no header and no content, all it does is instruct the browser to use the cache. The cached response has headers for the other site and it throws an access error.
These two requests should not be answered with a 304 since they are not equivalent.
If-None-Match means that pages are identified with en ETag. An arbitrary string generated by the application to identify a cachable version of a page.
You should modify the application to generate different ETag for different Origin.

Related

CORS Barrier from subdomain

I use my Web application in a subdomain also, I use a different subdomain for the interface objects.
That's the problem: CORS
Fonts are not installed because of cors barrier.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at
https://assets.example.com/fonts/simple-line-iconsc05f.ttf?thkwh4.
(Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
Application:
https://ap.example.com
Assets:
https://assets.example.com
I added the root of Web application, .htaccess file:
<FilesMatch "\.(ttf|otf|eot|woff|svg|woff2)$">
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
</IfModule>
</FilesMatch>
Also, nginx.conf file:
server {
...
location ~* \.(eot|ttf|woff|woff2)$ {
add_header 'Access-Control-Allow-Origin' '*';
}
...
}
Nevertheless, I'm still stuck in the cors barrier.
It has been tried many times with cache and different browsers. The result has not changed.
You can try this:
location / {
if ($request_filename ~* ^.*?/([^/]*?)$) {
set $filename $1;
}
if ($filename ~* ^.*?\.(eot)|(ttf)|(woff)|(jpg)|(png)|(css)|(js)$){
add_header 'Access-Control-Allow-Origin' "*";
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'User-Agent,Keep-Alive,Content-Type,X-Api-Token';
}
}
#Editor, whilst the solution from #Sahipsiz might work, CORS is a complex topic, and as per my previous comment, that solution is technically incorrect (even though it may have solved your symptom, the underlying problem is still there)...
First off, if your browser decides that CORS is in play, it will send the Origin request header, containing the full domain of the requesting page, e.g.:
Origin: https://ap.example.com
If the request doesn't include the Origin request header, then this isn't a CORS request, and you don't need to do anything CORS-related.
If you are sure that you don't need support for cookies to be passed to/from the assets domain, you can simply respond to a CORS request by including this response header:
Access-Control-Allow-Origin: *
However, if you do need cookie support, you'll need to include these two response headers:
Access-Control-Allow-Origin: <value of Origin request header>
Access-Control-Allow-Credentials: true
So in your case, you would respond with this:
Access-Control-Allow-Origin: https://ap.example.com
Access-Control-Allow-Credentials: true
In some cases (which may well not apply to you, since you're just retrieving fonts), prior to making the main GET/POST/PUT/DELETE request, your browser will first make an additional 'preflight' OPTIONS request - this is basically the browser asking permission to make the main request. The OPTIONS request includes a number of CORS-specific request headers, and you need to return some 'matching' CORS response headers to this OPTIONS request (but no response body). If you do this correctly, the browser will then make the main request.
For that OPTIONS request, you should return the following CORS response headers:
Access-Control-Allow-Origin: <value of Origin request header>
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: <value of Access-Control-Request-Method request header>
Access-Control-Allow-Headers: <value of Access-Control-Request-Headers request header>
Those response headers tell the browser that you are OK with the GET/POST/DELETE/PUT request it's about to make.
You can optionally also pass the following response header to the OPTIONS request (in addition to the four defined above):
Access-Control-Max-Age: 86400
which tells the browser to cache the OPTIONS response headers - this stops it from making the preflight request every time.
CORS ain't easy.

“Access-Control-Allow-Origin header contains multiple values” error

I'm getting mirriad of errors trying to do an ajax call in a reactjs app using axios. I have an api that lives at a subdomain and making calls from the main domain.
.htaccess:
Header add Access-Control-Allow-Origin: "*"
Header add Access-Control-Allow-Credentials: "true"
Header add Access-Control-Allow-Methods: "GET,HEAD,OPTIONS,POST,PUT"
Header add Access-Control-Allow-Headers: "Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers"
ajax headers in reactjs (using axios):
var options = {
method: 'GET',
url: 'http://admin.mysite.com/menus/5',
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET,HEAD,OPTIONS,POST,PUT',
'Access-Control-Allow-Headers': 'Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers'
}
}
I've tried making changes to each of these but get different errors. If I have the Header add Access-Control-Allow-Origin: "*" it complains about double origins. If I remove it I I get an error about Access-Control-Allow-Origin is not allowed by Access-Control-Allow-Headers in preflight response other changes has responded with Access-Control-Allow-Headers is not allowed by Access-Control-Allow-Headers in preflight response
I'm using wordpress as a headless CMS and tapping into the restful api to pull the data I need. I have noticed if I removed all of this I can get my data fine but I can't post without fixing the cross domain issues.
If I remove it I I get an error about Access-Control-Allow-Origin is not allowed by Access-Control-Allow-Headers in preflight response other changes has responded with Access-Control-Allow-Headers is not allowed by Access-Control-Allow-Headers in preflight response
Both those error messages are happening because in your frontend JavaScript code you have this:
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET,HEAD,OPTIONS,POST,PUT',
'Access-Control-Allow-Headers': 'Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers'
}
You need to remove that entire headers option from your request code.
The reason is, all the Access-Control-Allow-* headers are response headers that servers must return. The only effect you’ll have by sending them as request headers is to cause exactly the kinds of errors cited in the question.
If the reason you’re adding them is that your .htaccess settings on the server side for the API endpoint you’re sending the request to aren’t making the server send the right response headers, then you need to figure that out and fix that on the server side. Sending additional request headers from the client side isn’t going to fix that problem.
One suggestion you might try for your .htaccess: instead of Header add, use Header set:
Header set Access-Control-Allow-Origin: "*"
Header set Access-Control-Allow-Credentials: "true"
Header set Access-Control-Allow-Methods: "GET,HEAD,OPTIONS,POST,PUT"
Header set Access-Control-Allow-Headers: "Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers"
Header set tells Apache to overwrite/clobber any existing value that might already be a set for a particular header, whereas Header add tells it to just add a header with the name and value given, without overwriting any header that might already be set with that name.
So Header add can cause multiple headers with the same name to be sent in a response, in which case the browser treats it as a single header with multiple values. You don’t want that.

Node-Express-CORS issue

Ionic 2
I am using login provider but when i set the access control to
res.header('Access-Control-Allow-Origin', '*');
It is not working
But it works properly when i use
res.header('Access-Control-Allow-Origin', 'http://localhost:8100');
It is working
but now i want to deploy my app up on phone device i need to set it to wild card res.header('Access-Control-Allow-Origin', '*');. since my app on phone not working on http://localhost:8100 anymore
Anyone can help me solve this problem ?
If you are making a preflighted request then the wildcard is forbidden in the Access-Control-Allow-Origin header.
You can read the Origin request header in order to find out the origin. Then you can test it against a list of allowed origins (you could also assume that any origin is OK, but for a preflighted request there is a good chance that complete public access would be a security risk). Finally you can copy it into the Access-Control-Allow-Origin response header.
How is your HTTP request from your app looks like?
Look for "Types of CORS requests" in this article.
If your HTTP request is a simple one, i.e.
Method is HEAD, GET, or POST
Only have these headers
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type of application/x-www-url-encoded, multipart/form-data, or text/plain
If your HTTP request is a simple one, preflight is not needed. And Access-Control-Allow-Origin with * is accepted by the mobile app.
Otherwise, a preflight request will be made (i.e. OPTION request) and Access-Control-Allow-Origin of * will be ignored. It must be fully specified like http://localhost:8100.

Is there a downside to always returning Access-Control-Allow-Credentials?

A weird CORS question...
I have code in my example.com server which returns the Access-Control-Allow-Origin response header for all POST & GET requests where the Origin request header is passed and it has a value of an example.com sub-domain (superman.example.com, batman.example.com, etc.).
I now need to be able to make AJAX calls passing cookies, so I need to be able to return the Access-Control-Allow-Credentials response header if the request includes cookies.
I could add an additional check to return the Access-Control-Allow-Credentials response header if I see the Cookie request header, but for simplicity, I'm wondering if there is any downside to always returning the Access-Control-Allow-Credentials response header for all GET/POST requests from my sub-domains, where the Origin request header is specified.
Here's my code (it's a Tcl iRule, FWIW):
when HTTP_REQUEST priority 200 {
if { ( [HTTP::method] equals "OPTIONS" ) and
( [HTTP::host] ends_with "example.com"] ) and
( [HTTP::header exists "Access-Control-Request-Method"]) } {
HTTP::respond 200 "Access-Control-Allow-Origin" [HTTP::header "Origin"] \
"Access-Control-Allow-Methods" "POST, GET, OPTIONS" \
"Access-Control-Allow-Headers" [HTTP::header "Access-Control-Request-Headers"] \
"Access-Control-Max-Age" "86400"
} elseif { ( [HTTP::host] ends_with "example.com"] ) and
( [HTTP::header exists "Origin"]) } {
# CORS GET/POST requests - set cors_origin variable
set cors_origin [HTTP::header "Origin"]
}
}
when HTTP_RESPONSE {
# CORS GET/POST response - check cors_origin variable set in request
if { [info exists cors_origin] } {
HTTP::header insert "Access-Control-Allow-Origin" $cors_origin
HTTP::header insert "Access-Control-Allow-Credentials" "true"
}
}
I am aware that if I return the Access-Control-Allow-Credentials response header, I have to specify a named (non-generic) Access-Control-Allow-Origin header (and that may have Vary header issues), but is there anything else I need to be aware of?
If you take defence in depth into consideration, unconditionally including
Access-Control-Allow-Credentials: true
in responses is a bad idea. Your app may indeed be vulnerable to HTTP-header injection. Imagine a situation where the attacker is able to inject—perhaps via a query parameter in the URL—exactly one arbitrary HTTP header in the response. In that case, the attacker would effectively be able to force responses to contain the following headers,
Access-Control-Allow-Origin: https://attacker.com
Access-Control-Allow-Credentials: true
which would leave the content wide open to cross-origin attacks from https://attacker.com.
James Kettle mentions something similar in his AppSecUSA 2016 talk, entitled Exploiting CORS Misconfigurations for Bitcoins and Bounties:
It's quite common to find classic HTTP-header-injection vulnerabilities where, for whatever reason, you can't inject into the response content. You can't just inject malicious HTML; the only thing you can do is set HTTP
headers. And CORS offers a brilliant way of exploiting this because you can just say
This content is open to everyone!
using CORS and then attackers can get hold of that [...]

Node Express Mongoose MongoDB CORS failure

I am using Node/Express/Mongoose/MongoDB on a Debian VPS webserver but for some reason the online CORS request is not firing. Let me just say that everything works perfectly on my local server.
When I upload it to my Debian VPS webserver however the cors request never goes through. I know this because the debug logs never fire. The MongoDB server is running AND the node/express server is running. I have npm reinstalled express/mongoose and even the cors addon MANY times and do not think it's an issue with those...
I have tested things on the server with cURL -H w/ the -origin flags. THE RESPONSES RETURN CORRECTLY in the console. This leads me to believe that the CORS requests are being blocked somehow (maybe by the browsers??) and the express servers are never even reached. I have tried starting browsers with no security flags to no avail also... ONE strange fact is that when the responses do return w/ cURL, they sometimes list different origins even though I specify one origin with the flag. Confusing...
I have tried changing access-origins MANY different times and ways. I have tried allowing all of them. I have tried allowing the ones specific to the requests... I have tried using the apache2 header mod and using an .htaccess file to allow cors. I have also tried the PHP header for it to no avail.
url: www.kensnote.com
Browser error responses are as follows:
Chromium-browser: "Failed to load resource"
Firefox: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:10005/threadpreview. (Reason: CORS request failed).
Firefox Firebug Request Headers:
Accept application/json, text/javascript, /; q=0.01
Accept-Encoding gzip, deflate Accept-Language en-US,en;q=0.5
Cache-Control max-age=0 Connection keep-alive DNT 1 Host
localhost:10005 If-None-Match W/"ssUy2L+Up13MCm2LISgPtQ==" Origin
http://www.kensnote.com Referer http://www.kensnote.com/
User-Agent Mozilla/5.0 (X11; Linux i686; rv:39.0) Gecko/20100101
Firefox/39.0
In a browser implementing CORS, each cross-origin GET or POST request
is preceded by an OPTIONS request that checks whether the GET or POST
is OK.
Basically, for CORS, Firefox will send a preflight options check before the real request.
In your server code, you should send an OK response to the OPTIONS request. Check the following example code that can be used in a route (or middleware):
res.header("Access-Control-Allow-Headers", "Authorization, Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Methods", "PATCH, POST, GET, PUT, DELETE, OPTIONS");
if ('OPTIONS' === req.method) {
return res.send(200);
}

Resources