Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I disable Django's csrf protection only in certain cases?

I'm trying to write a site in Django where the API URLs are the same as user-facing URLs. But I'm having trouble with pages which use POST requests and CSRF protection. For example, if I have a page /foo/add I want to be able to send POST requests to it in two ways:

  1. As an end user (authenticated using a session cookie) submitting a form. This requires CSRF protection.
  2. As an API client (authenticated using a HTTP request header). This will fail if CSRF protection is enabled.

I have found various ways of disabling CSRF, such as @csrf_exempt, but these all disable it for the entire view. Is there any way of enabling/disabling it at a more fine-grained level? Or am I just going to have to implement by own CSRF protection from scratch?

like image 813
lucas Avatar asked Jul 07 '12 10:07

lucas


People also ask

How can I be exempt from CSRF?

You can use the csrf_exempt decorator to disable CSRF protection for a particular view.

Is it safe to disable CSRF?

Yes, it is safe to disable if you have a different authentication mechanism that cannot be cloaked. For internal enterprise applications, not much of a concern. We had to disable it because it was interfering with our existing authentication mechanism.

What is CSRF and how does Django protect against this attack?

CSRF protection works by checking for a secret in each POST request. This ensures that a malicious user cannot “replay” a form POST to your website and have another logged in user unwittingly submit that form. The malicious user would have to know the secret, which is user specific (using a cookie).

Where does the CSRF token reside in the HTTP request object in Django?

The CSRF token is like an alphanumeric code or random secret value that's peculiar to that particular site. Hence, no other site has the same code. In Django, the token is set by CsrfViewMiddleware in the settings.py file.


2 Answers

Modify urls.py

If you manage your routes in urls.py, you can wrap your desired routes with csrf_exempt() to exclude them from the CSRF verification middleware.

for instance,

from django.views.decorators.csrf import csrf_exempt urlpatterns = patterns(     # ...     # Will exclude `/api/v1/test` from CSRF      url(r'^api/v1/test', csrf_exempt(TestApiHandler.as_view()))     # ... ) 

Alternatively, as a Decorator

Some may find the use of the @csrf_exempt decorator more suitable for their needs

for instance,

from django.views.decorators.csrf import csrf_exempt from django.http import HttpResponse  @csrf_exempt def my_view(request):     return HttpResponse('Hello world') 
like image 103
Jossef Harush Kadouri Avatar answered Sep 29 '22 23:09

Jossef Harush Kadouri


There is a section of Django's CSRF Protection documentation titled View needs protection for one path which describes a solution. The idea is to use @csrf_exempt on the whole view, but when the API client header is not present or invalid, then call a function annotated with @csrf_protect.

like image 33
Daniel Trebbien Avatar answered Sep 29 '22 23:09

Daniel Trebbien