I have to make CORS with content type JSON. This makes the browser send first an OPTIONS request, specifying origin and so on. Then the server should answer with allowed domains, methods, etc. If this goes well, the browser sends the actual request.
My problem is that the server needs authentication for the actual request but ALSO for the OPTIONS request. But the browser doesn't send the authentication headers with the OPTIONS request.
I'm using JQuery and the ajax() function. I tried adding "withCredentials: true", and add the Authorization header, but this not affect the OPTIONS request, it still doesn't send any credentials.
Any ideas? Thanks in advance.
The preflight request is only meant to verify if the CORS request itself is allowed. Therefore, cookies are never included in the preflight request. You'd have to validate the user during the actual request.
Actually, Chrome will send the cookies w/ the preflight request if withCredentials=true whereas Firefox will not. Sounds like they've implemented the spec differently.
Related
This answer states, that one way X-Requested-With header prevents CSRF attacks is that if server doesn't allow it then a modern browser wont allow javascript code to add this header. And if header is present server can be sure that request didn't originate from another page a user might have opened.
To my understanding the way browser determines whether a custom header is allowed or not in an ajax request is by making a preflight request. And then a server responds with header Access-Control-Allow-Headers. Which contains list of headers allowed for a request in question. So if servers returns an empty list then CORS ajax calls couldn't have xhr header present. Indicating different origin.
So my question is whether preflight request is triggered if origin is the same. Because if they are, then server would say dont add any header, and if browser doesn't then to server a request from its own origin would be indistinguishable from another origin.
So my question is whether preflight request is triggered if origin is the same.
No, it isn't.
Because if they are, then server would say dont add any header, and if browser doesn't then to server a request from its own origin would be indistinguishable from another origin.
The browser not sending a preflight request doesn't stop the server from testing the actual request for a header and throwing an error if it isn't present.
I have receive the following response when trying to access an API via an ajax request in Chrome:
"Failed to load http://localhost:1880/api_resource: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin http://localhost:3000 is therefore not allowed access."
As you can see from the message, both client and API are running locally.
I understand that this situation relates to a CORS cross origin request. I see that there are similar questions about this on stack overflow, but from those answers I do not understand what the message is telling me and where it comes from.
Specifically I understand that the response header "Access-Control-Allow-Origin" must be set (typically to '*') to allow access to the API from a different domain to the one on which the API is being served. But the message seems to relate to the request and not the response, and as far as I am aware, no request ever reaches the API.
What is a preflight request and how is it failing?
As I now understand it, modern browsers will issue a 'preflight' request before the actual cross origin request. This preflight request uses the 'OPTIONS' HTTP verb along with the CORS headers Access-Control-Request-Method and Access-Control-Request-Headers to which it expects to see a response with valid Access-Control-Allow-Origin in the header that indicates that the server understands the CORS protocol and will allow the actual (GET/POST/PUT) request.
The message "Response to preflight request doesn't pass access control check" means that the browser did not see a valid "Access-Control-Allow-Origin" header in the Options response.
In my case this was because the server (implementing a REST API) was set up to respond correctly to PUT and POST requests but not setup to respond to OPTIONS requests with the CORS headers.
in my case the problem was for my website address, i'm calling all apis from the same server but i got this error.
my website address is sateh.ir
so im my ajax request i set the url: http://sateh.ir/api/...
after getting this error and working on it for some hours, i got that i had to set ajax url to: http://www.sateh.ir/api/...
i dont know why my website cant understand that i'm calling api from the same server if i dont put 'www', but that was my problem at all.
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.
I am trying to make POST request via AJAX from abc.com to URL from xyz.com (which is a Django application).
I am getting CSRF token by making a GET request to a URL on xyz.com, but the token changes when an OPTIONS request is made to xyz.com in the preflighted request.
Is there any way to get the response of OPTIONS request in the preflighted request ?
Note:
I am following instructions from following sources :
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
https://developer.mozilla.org/en/docs/HTTP/Access_control_CORS
http://www.html5rocks.com/en/tutorials/cors/
Django CSRF protection will allow OPTIONS requests, so no problem with the first stage:
https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#how-it-works
If I understand correctly, you then want the next request (e.g. a cross-domain POST) to be allowed through. For this to work and get past Django's CSRF protection, the request must send a CSRF token (in POST data or in header for AJAX) and a matching CSRF cookie.
Now, cross-domain restrictions make it impossible for abc.com to set or read a cookie for xyz.com, whether from javascript or from a server side response. Therefore, this approach is impossible.
Instead you will have to apply #csrf_exempt to the view. This would allow any site to post to it. Therefore, you'll need to build in some other protection to the view. You are, of course, on your own in checking the security of your protection. Remember that 'Referer' and 'Origin' headers can easily be forged with something as basic as curl.
See django-cors-headers, you may find it how it works more suitable to solve your problem:
https://github.com/ottoyiu/django-cors-headers/
Django-rest-framework recommends http://www.django-rest-framework.org/topics/ajax-csrf-cors
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.