How to send the right Access-Control-Allow-Origin value for responses to cross-origin requests with credentials/cookies - ajax

I have a setup where a client application is running on a different domain (http://www.example.com) than the server application (http://www.example2.com). I've got the cross domain AJAX requests working except that I cannot figure out a way to send cookies with the request without having to add the Access-Control-Allow-Origin response header for each possible domain. Is there a way to set this up without having to specify a list of domains in that header? I'm aware of the security implications so I guess what I'm really asking is ... is there another framework separate from CORS that I can use which will allow this type of setup and at the same time allow any domain for the client application? I tried JSONP but that did not work out (could not send the cookie with the JSONP request). Is there something else I should try other than CORS and JSONP? Thanks.
EDIT: This is not a duplicate of the question mentioned in the duplicate notification. I'm already aware of the withCredentials flag. The problem is that I don't want to have to specify a list of domains in the CORS response header. I want something equivalent to setting that value to '*', but setting it to '*' is not allowed if sending a cross domain AJAX request that contains cookies.

Related

CORS with client https certificates

I have a site with two https servers. One (frontend) serves up a UI made of static pages. The other (backend) serves up a microservice. Both of them happen to be using the same (test) X509 certificate to identify themselves. Individually, I can connect to them both over https requiring the client certificate "tester".
We were hiding CORS issues until now by going through an nginx setup that makes the frontend and backend appear that they are same Origin. I have implemented the headers 'Access-Control-Allow-Origin', 'Access-Control-Allow-Credentials' for all requests; with methods, headers for preflight check requests (OPTIONS).
In Chrome, cross-site like this works just fine. I can see that front-end URLs and backend URLs are different sites. I see the OPTIONS requests being made before backend requests are made.
Even though Chrome doesn't seem to need it, I did find the xmlhttprequest object that will be used to perform the request and did a xhr.withCredentials = true on it, because that seems to be what fetch.js does under the hood when it gets "credentials":"include". I noticed that there is an xhr.setRequestHeader function available that I might need to use to make Firefox happy.
Firefox behaves identically for the UI calls. But for all backend calls, I get a 405. When it does this, there is no network connection being made to the server. The browser just decided that this is a 405 without executing any https request. Even though this is different behavior from Chrome, it kind of makes sense. Both the front-end UI and backend service need a client certificate to be chosen. I chose the certificate "tester" when I connected to the UI. When it goes to make a backend request, it could assume that the same client certificate should be used to reach the back-end. But maybe it assumes that it could be different, and there is something else I need to tell Firefox.
Is anybody here using CORS in combination with 2 way SSL certificates like this, and had this Firefox problem and fixed it somewhere. I suspect that it's not a server-side fix, but something that the client needs to do.
Edit: see the answer here: https://stackoverflow.com/a/74744206/537554
I haven't actually tested this using client certificates, but I seem to recall that Firefox will not send credentials if Access-Control-Allow-Origin is set to the * wildcard instead of an actual domain. See this page on MDN.
Also there's an issue with Firefox sending a CORS request to a server that expects the client certificate to be presented in the TLS handshake. Basically, Firefox will not send the certificate during the preflight, creating a chicken and the egg problem. See this bug on bugzilla.
When using CORS with credentials (basic auth, cookies, client certificate, etc.):
Access-Control-Allow-Credentials must be true
Access-Control-Allow-Origin must not be *
Access-Control-Allow-Origin must not be multi-value (neither duplicated nor comma-delimited)
Access-Control-Allow-Origin must be set to exactly the value from the request's Origin header in order for the request to work (either hard-coded that way or if it passes a whitelist of allowed values)
The preflight OPTIONS request must not require credentials (including the client certificate). Part of the purpose of the preflight is to ask what is allowed in a CORS request, and therefore sending credentials before knowing if they are allowed is incorrect.
The preflight OPTIONS request must return a 200-level response, generally 204
Note: For Access-Control-Allow-Origin, you may want to consider allowing the value null since redirect chains (like the ones typically used for OAuth) can cause that Origin value in a request from a browser.

Cookie in AJAX response from other domain not honored - are there workarounds

I have a server-side API on the domain api.example.com
User is visiting www.website.com where a script makes an XmlHttpRequest to api.example.com and gets a response with a cookie.
It appears the API's response cookie is not honored by the HTTP agent.
I'm aware of the non-cross-domain-leaking-cookie policy, but I thought the domain here would be api.example.com. Seems I guessed wrong.
Is there some other way that my API on api.example.com could remember user data from one site to another? If not, how could services like Criteo and other retargeting sites work, from this point of view?
Make sure your API set:
Access-Control-Allow-Credentials header to true in possible preflight response and regular response,
Access-Control-Allow-Origin header to value of the origin from the actual request,
and client sets XMLHttpRequest.withCredentials to true.

Is it possible to enable cross domain request using XHR?

I've a server named, foo.com where my application is running and accessing a service available on a different domain bar.foo.com.
With the simple XHR request to bar.foo.com/getUsers, I'm getting an error saying, No 'Access-Control-Allow-Origin' header is present. I do not want to use JSONP as a fallback to cross-domain issue.
Is there any easy fix I can do on server level to enable cross subdomain requests while XHRing?
It appears that I need to set allow-cross-domain headers on server when a response is returned as suggested by #Blender above.
Or I can use xdomain library which uses PostMessage API to enable cors. With this I can even read iframe's content served by different domain.

Why is ExtJS sending an OPTIONS request to the same domain?

I'm loading my script on a domain and sending some data with POST and the use of Ext.Ajax.request() to that same domain.
Somehow the dev-tools show me, that there is a failed OPTIONS request.
Request URL : myurl-internal.com:8090/some/rest/api.php
Request Headers
Access-Control-Request-Headers : origin, x-requested-with, content-type
Access-Control-Request-Method : POST
Origin : http://myurl-internal.com:8090
It's both HTTP and not HTTPS. Same port, same host ... I don't know why it's doing this.
The server can't handle such stuff and so the request fails and the whole system stops working.
It's not really specific to Ext JS -- see these related threads across other frameworks. It's the server properly enforcing the CORS standard:
for HTTP request methods that can cause side-effects on user data (in
particular, for HTTP methods other than GET, or for POST usage with
certain MIME types), the specification mandates that browsers
“preflight” the request, soliciting supported methods from the server
with an HTTP OPTIONS request header, and then, upon “approval” from
the server, sending the actual request with the actual HTTP request
method.
If you're going to use CORS, you need to be able to either properly handle or ignore these requests on the server. Ext JS itself doesn't care about the OPTIONS requests -- you'll receive the responses as expected, but unless you do something with them they'll just be ignored (assuming the server actually allows whatever you're trying to do).
If you are NOT intending to use CORS (which sounds like you aren't purposefully going cross-domain) then you need to figure out why the server thinks the originating domain is different (I'm not sure about that). You could also bypass CORS altogether by using JsonP (via Ext's JsonP proxy).
Use relative url instead of absolute, then you will get expected result.
use before request
Ext.Ajax.useDefaultXhrHeader = false

Can an AJAX response set a cookie?

Can an AJAX response set a cookie? If not, what is my alternative solution? Should I set it with Javascript or something similar?
According to the w3 spec section 4.6.3 for XMLHttpRequest a user agent should honor the Set-Cookie header. So the answer is yes you should be able to.
Quotation:
If the user agent supports HTTP State Management it should persist,
discard and send cookies (as received in the Set-Cookie response
header, and sent in the Cookie header) as applicable.
Yes, you can set cookie in the AJAX request in the server-side code just as you'd do for a normal request since the server cannot differentiate between a normal request or an AJAX request.
AJAX requests are just a special way of requesting to server, the server will need to respond back as in any HTTP request. In the response of the request you can add cookies.
For the record, be advised that all of the above is (still) true only if the AJAX call is made on the same domain. If you're looking into setting cookies on another domain using AJAX, you're opening a totally different can of worms. Reading cross-domain cookies does work, however (or at least the server serves them; whether your client's UA allows your code to access them is, again, a different topic; as of 2014 they do).
Also check that your server isn't setting secure cookies on a non http request. Just found out that my ajax request was getting a php session with "secure" set. Because I was not on https it was not sending back the session cookie and my session was getting reset on each ajax request.

Resources