Django: Forcing CSRF token on all responses - python

My website has an AJAX POST view that can be called from any page on the app (event tracking). This view is protected by CSRF. In some cases, the CSRF cookie is not set, and the POST call fails.
Instead of manually decorating all views with #ensure_csrf_cookie, I'm thinking of writing I created a middleware that enforces Django to set the CSRF cookie on all responses. Is this approach correct? Does it create a security flaw I'm not aware of?
Update: here is the middleware code:
from django.middleware.csrf import get_token
class ForceCsrfCookieMiddleware(object):
def process_request(self, request):
get_token(request)

No, there is no problem as long as you're not rendering the csrf token inside a form that posts to an external site (but that would be a problem anyways, no matter where you implement it). You can set it on a middleware, or some views, or on all views, it doesn't matter.
The CSRF protection is only made to ensure that the request is coming from your site. No matter how often you set the cookie, if the request includes the correct CSRF token it means that the request is indeed coming from your site, because only your site can access your cookies. (of course this only holds if you are not leaking the CSRF token to third parties, for example by sending it to other sites)
In few words, this is how it works:
The server sets a cookie with a random value in the response
Your site reads that value and sends it to the server when posting data
Since cookies can only be accessed from the same domain that set them, there is no way for another site to read that cookie. Therefore, whenever you receive a request that has the right csrf token, you are assured that that request is coming from your site.
For a very good explanation of CSRF, have a look at this article: http://www.gnucitizen.org/blog/csrf-demystified/

Related

What are some examples where programmers might want to use csrf_exempt?

By default, Django offers protection against Cross-Site Request Forgery (CSRF) attacks by sending a CSRF token to webpages it generates, which is then sent back with requests to validate them. This is detailed here.
Django provides the csrf_exempt decorator to disable this behaviour. What are some good reasons programmers might want to use it?
This details why it could be dangerous, I'm interested in how it could be useful.
I'm looking for answers that are not obvious (e.g. not knowing how to use the CSRF protection or disabling it temporarily).
For instance, we use it for an interface where another party posts data programmatically. Thus, they can never get a csrf token. The page is, however, basic-auth secured.
Project I am working on has tiny embedded devices talking HTTP to a django application server over a VPN. The HTTP client on these is very primitive, so we disable CSRF.
Whenever your client sends a request to the server, some confidential information will be send along with the request. The CSRF token prevents a malicious site from abusing that information. Particularly, this prevents a malicious site from sending a forged request that uses your cookies and/or session to authenticate your client and authorize the action. Any information that is automatically and implicitly send on every request by your client is vulnerable to a CSRF attack (though not all information might actually be useful in such an attack).
The #csrf_exempt decorator can safely be used to avoid the CSRF protection mechanism if and only if the server-side actions that are the result from the request do not depend on the authentication and authorization that is sent implicitly by the client. Examples are token-based authentication and HTTP Basic authentication. For these forms of authentication, the client must explicitly sent the token or credentials for each request. If a malicious site forges a request, it cannot send the required authentication information to the server (unless a different vulnerability exposes that information), and the request is denied. In such cases, CSRF does not offer any extra protection.

CSRF error django rest framework when using session auth

I am building an api for interfacing with mobile applications that requires users to login. Just using session auth gives me a csrf error. I was able to fix it by providing credentials in basic auth, but I don't think this is ideal. This will be my first time developing for mobile devices. I was planning on using cordova, and I don't know if there is a way to store credentials on the user's device, or if the session data will be automatically stored on the devices. If the session data will be stored on the mobile devices automatically, that would be the ideal route to go. Has anyone else had similar issues with DRF session auth, or advice on if this is the best route to go or not?
Update:
I was able to get the csrf error to go away by using this from another post:
from rest_framework.authentication import SessionAuthentication
class NoCsrfSessionAuthentication(SessionAuthentication):
def enforce_csrf(self, request):
return
But this seemed to cause an error with the request.data parameter. It kept returning an empty query dict.
If you want to use session auth, but are confident that you can give up CSRF protection for a given view, the
#csrf_exempt
decorator will do just that. (If you are using class-based views, check out this: https://stackoverflow.com/a/14379073/1375015)
Since you are using session based authentication, your mobile applications must be storing some kind of session cookie. Therefore, you should also be able to store the csrftoken cookie and send it along with your http requests. However, even then I had some troubles with the django CSRF protection framework in the past.
Maybe switching to token authentication is an option?

How to use Flask-WTF CSRF protection for Single Page Apps?

I noticed that tokens generated by Flask-WTF expire in one hour and a different one is generated every request. This will cause problems in SPAs when a page has been opened longer than an hour. XHR requests made after one hour after page-load will start failing, even if the user was active.
My workaround is to set a new token in the browser in each API call. In the server, all API responses contain a freshly-generated token:
from flask_wtf.csrf import generate_csrf
def api_response(data, error=None):
response = {"csrftoken": generate_csrf(), "data":data}
...
return make_response(jsonify(response), response_code)
In the browser we set the csrftoken on each API response.
then(function(result) {
if(result.csrftoken) csrftoken=result.csrftoken;
callback(result);
})
Is this method still safe and fast? Is there a better way to handle this? I am not too sure about using generate_csrf directly.
No, there is no other way to use the CSRF protection in Flask-WTF. When you need a CSRF token, you need to generate one and use it. There should be no problem with generating it like you do. It is still generated and validated the same way on the server, and transmitted over the same channel to the client.

Manual CSRF Verification

I have a e-commerce Django application that automatically verifies all incoming POST requests with CSRF token using the CSRFViewMiddleware.
Now, for payments, I'm using a payment gateway where I pass the relevant details along with the csrfmiddlewaretoken so that it is returned back to me when the transaction on 3rd party site is complete. So, when the user is re-directed back to my site, I get a
403 Forbidden
CSRF verification failed. Request aborted.
How do I fix this? Is there any way I can manually check csrftoken using request.POST.get('csrfmiddlewaretoken') or something like that.
I would prefer not to bypass csrf totally as I want it to be secure (atleast, as much as possible).
Edit I understand csrfmiddleware token needs to be passed in the header but I cannot do that as there are only limited things I can do with a 3rd party payment gateway.
From this snippet, I get a feeling that you may not quite understand what is CSRF:
I have a e-commerce Django application that automatically verifies all
incoming POST requests with CSRF token using the CSRFViewMiddleware.
That's part your problem right there. CSRF is only for those requests that are made from your site, to your site (see OWASP's definition of CSRF):
Cross-Site Request Forgery (CSRF) is a type of attack that occurs when
a malicious Web site, email, blog, instant message, or program causes
a user’s Web browser to perform an unwanted action on a trusted site
for which the user is currently authenticated.
You need CSRF tokens only on those forms that are generated by your site, and post to your site. In addition, any javascript code that sends a POST request should also be properly protected.
For all other end points - for example, if some payment provider is posting the result back to your application - you do not want to enable CSRF protection otherwise the requests will continue to fail.

How to get an initial CSRF token when working with Django Rest Framework

I am creating an API with the Django Rest Framework. Users are still going to need to get a CSRF token to make POST, PUT, PATCH and DELETE calls. What is the best practice for the user initially getting a CSRF token? I am using TokenAuthentication. So I just need to allow the API to take and username and password and send back the Token. After that I don't need the CSRF token.
Do I have to add a step that will allow them to get CSRF token using a GET method call which will return a token?
I am looking for suggestions on how to best approach this.
With an API you are just about to open a gate to process requests on your server without any session and browser. CSRF tokens are just validating form requests to make sure it's sent from your website. As far as I know it's absolutely ok to turn off CSRF protection for APIs.
You can use csrf_exempt decorator for this.
Read this article to learn more about CSRF and Web API protection.

Categories