CSRF in Ajax requests - ajax

As I know Same-origin policy forces an Ajax request to be issued only to the domain the script was loaded from.My application does not make any cross domain ajax request. So are all my ajax requests safe from CSRF? or Do I need to use some token for same origin Ajax requests as well?

CSRF is also useful in AJAX request , anyone can access AJAX domain path from other way e.g CURL, so better to add CSRF token to prevent access, it would also good in AJAX request even cross origin request blocked

Related

Ajax request to Django only succeeds if there is no sessionid cookie

I have sessions enabled in Django to use Django's authentication framework.
From a html page served by Django, and after authenticating as a user with sufficient permissions, I'm trying to send a PATCH request via JQuery's ajax() function, and I'm getting HTTP 403 errors with the response detail CSRF Failed: CSRF token missing or incorrect.
What I've done so far:
I'm including the correct csrf token in the X-CSRF-TOKEN header field.
I've set SESSION_COOKIE_HTTPONLY = False.
The cookie sent in the ajax request includes the sessionid. If I get rid of this sessionid, the request succeeds.To do so, I either delete the session cookies in the browser or edit the PATCH request in the browser's developer tools and resend it with the sessionid deleted from the Cookie header field. Obviously I need to re-login as soon as I refresh the page, but in the meantime, I can PATCH to my heart's content.
So far I couldn't find out why the presence of the sessionid cookie makes Django deny the request.

How to handle CSRF in preflighted CORS POST request in django?

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

Send credentials in preflighted request (CORS)

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.

CSRF and Ajax: Do I need protection?

Do I need to use csrf tokens in my ajax requests?
I think that someone tricking my users to execute malicious ajax requests from another site, to my site, will fail because of the origin policy, which is handled by the browser, am I right?
I don't care about duplicated requests when using ajax, I'm only asking about the attacks.
Am I at risk if I don't use csrf in my ajax requests?
As per my research,
We can reduce the vulnerability by using POST request(for the request which will take side affect). But thing is that we can forge the POST request as well with form submission, cause same origin policy will not applies plain html for submissions. But it applies to request which are getting generated with JS.
So if you use ajax POST request and you are safe if you are using JSON payload.
Cause url encoded payload(POST request) can be forged with form submission from other sites.
If you use JSON, as it is not possible to send plain text pay load(with out urlform encoded) with html form submission you are safe. Because with ajax POST request if you use urlform encoded data payload it can be forged with POST form submission.
This is how we solved the problem with CSRF token in Ajax requests
http://mylifewithjava.blogspot.com/2010/11/implicit-csrf-protection-of-ajax_22.html
The fact that you are using Ajax doesn't mean that others have to as well. Your server won't be able to distinguish a request made by XHR from one made by <form> submission. (Yes XHR usually adds a header identifying itself, but this is not hard to spoof.)
So yes, you do need to consider CSRF attacks.
Edit
Django have a POC, which is why they and Ruby on Rails now implement CSRF protection on AJAX requests.
Once again, please check your facts before downvoting, and explain what the downvote is for.

Is exposing a session's CSRF-protection token safe?

Django comes with CSRF protection middleware, which generates a unique per-session token for use in forms. It scans all incoming POST requests for the correct token, and rejects the request if the token is missing or invalid.
I'd like to use AJAX for some POST requests, but said requests don't have the CSRF token availabnle. The pages have no <form> elements to hook into and I'd rather not muddy up the markup inserting the token as a hidden value. I figure a good way to do this is to expose a vew like /get-csrf-token/ to return the user's token, relying on browser's cross-site scripting rules to prevent hostile sites from requesting it.
Is this a good idea? Are there better ways to protect against CSRF attacks while still allowing AJAX requests?
UPDATE: The below was true, and should be true if all browsers and plugins were properly implemented. Unfortunately, we now know that they aren't, and that certain combinations of browser plugins and redirects can allow an attacker to provide arbitrary headers on a cross-domain request. Unfortunately, this means that even AJAX requests with the "X-Requested-With: XMLHttpRequest" header must now be CSRF-protected. As a result, Django no longer exempts Ajax requests from CSRF protection.
Original Answer
It's worth mentioning that protecting AJAX requests from CSRF is unnecessary, since browsers do not allow cross-site AJAX requests. In fact, the Django CSRF middleware now automatically exempts AJAX requests from CSRF token scanning.
This is only valid if you are actually checking the X-Requested-With header server-side for the "XMLHttpRequest" value (which Django does), and only exempting real AJAX requests from CSRF scanning.
If you know you're going to need the CSRF token for AJAX requests, you can always embed it in the HTML somewhere; then you can find it through Javascript by traversing the DOM. This way, you'll still have access to the token, but you're not exposing it via an API.
To put it another way: do it through Django's templates -- not through the URL dispatcher. It's much more secure this way.
Cancel that, I was wrong. (See comments.) You can prevent the exploit by ensuring your JSON follows the spec: Always make sure you return an object literal as the top-level object. (I can't guarantee there won't be further exploits. Imagine a browser providing access to the failed code in its window.onerror events!)
You can't rely on cross-site-scripting rules to keep AJAX responses private. For example, if you return the CSRF token as JSON, a malicious site could redefine the String or Array constructor and request the resource.
bigmattyh is correct: You need to embed the token somewhere in the markup. Alternatively, you could reject any POSTs that do have a referer that doesn't match. That way, only people with overzealous software firewalls will be vulnerable to CSRF.

Resources