A security discussion around csrf

580 views
Skip to first unread message

Toran Billups

unread,
Jan 30, 2013, 8:58:15 PM1/30/13
to django-res...@googlegroups.com
I was looking through the source code of APIView today to help me understand why my javascript client could do an http post w/out having to add the django csrf token to each $.ajax POST/PUT request that was being processed by the django rest framework.

I found this line

# Note: session based authentication is explicitly CSRF validated,
    # all other authentication is CSRF exempt.
    @csrf_exempt
    def dispatch(self, request, *args, **kwargs):

And later followed up w/ Tom on twitter to see if I understood the implementation.

The comment (and Tom's tweet) made it clear that this was using my django session csrf token value. And when I looked a little deeper the javascript client was passing my header (thanks to the http cookie I had) and sure enough this was passing both my django session id and the csrf token.

The issue I have is that a true csrf attack is still open to be exploited (scenario listed out below)

Example of an attack that is wide open today.

1.) a user logs into django app #1 (valid -legit user). (think banking web app)
2.) this user now has a cookie w/ the django session and csrf token
3.) this user navigates away to an "evil" website
4.) this "evil" website has a hidden html form that gets submitted when the user clicks another seemingly "legit" form on the page
5.) the hidden form that is posted takes advantage of the users session from the init login (step 1) to manipulate something in that web app w/out the users knowledge (think money transfer)

Step 5 would have been more difficult if the csrf token was required during the "evil" hidden form http POST but because the user had a legit session the view was csrf_exempt

I can implement my own middleware to require this token (to prevent attacks like the one I described above) ... but I'm curious if this could be a pull request assuming the community wants it fixed. So a big part of me asking this question is to get a discussion going about the philosophy behind the framework and see what others think / etc

Thank you in advance

Tom Christie

unread,
Jan 31, 2013, 1:49:26 AM1/31/13
to django-res...@googlegroups.com
If you believe you may have a legitimate security concern please *do not post to the group*. Please contact me privately, and we can discuss and resolve any issues.

Session authentication in REST framework *is* CSRF validated, it's just that Django's CSRF middleware gets applied by the auth class itself, rather than during the request middleware stage.

The most likely source of confusion is if you're posting to a view that uses 'permissions.AllowAny', (and that's also not accessing request.user anywhere in the view), in which case the request will never be authenticated, (because it doesn't need to be) and you won't see any CSRF errors.


--
You received this message because you are subscribed to the Google Groups "django-rest-framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-fram...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Tom Christie

unread,
Feb 3, 2013, 3:14:56 PM2/3/13
to django-res...@googlegroups.com
In case anyone else is concerned about this.

After this post, I set up a project to double check the CSRF behavior, which works as expected,
as well as following this up privately with Toran, and confirmed that he's in agreement this isn't an issue.

To re-iterate and be absolutely clear, Django's *regular CSRF middleware* is applied for session authentication, exactly as it would be if the view was not @csrf_exempt, except that it's applied during REST framework's authentication stage, rather than during the standard Django middleware stage.

To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-framework+unsub...@googlegroups.com.

Matthew Morrison

unread,
Feb 8, 2013, 11:05:48 PM2/8/13
to django-res...@googlegroups.com
I also questioned the CSRF behavior. After exchanging a few emails with Tom everything is now clear to me. Just to clarify and reiterate CSRF protection is absolutely in place in djangorestframework.

In case someone else finds themselves lost in the same confusion that I was, hopefully this will help.

There are a few things that make it appear to not work as you might expect. 

1. The first thing that you will probably notice is that you can spin up a simple Django application and submit a post request to an API view without providing a CSRF token and you will not receive a CSRF Token error. However, if you log in and retry the same post you will receive the CSRF error. Out of the box, a stock Django view will give you a CSRF token error in both scenarios. 

2. Another thing that you may notice is that the base APIView class's dispatch method is decorated with Django's csrf_exempt decorator.

3. Something that I was very confused about was Tom's reply where he mentioned that Django's CSRF middleware is applied for session authentication. Since CSRF protection needs to happen on each and every request, this did not seem adequate. Actually, it is not Django's standard authentication that Tom was referring to, it was djangorestframework's authentication which happens on each request inside of an APIView depending on which authentication_classes are configured for that view.

Because APIViews can both be used from a browser (which needs CSRF protection) or a server (which does not need CSRF protection) by default the CSRF protection is turned off. However, also by default an APIView has an authentication class called SessionAuthentication. This class will dynamically re-apply django's CSRF middleware if the current request object contains an active user. 

Hopefully this will help someone in the future who runs into similar concerns.

Thanks Tom for building a great framework and for putting up with all of my questions!

Toran Billups

unread,
Feb 9, 2013, 9:27:26 AM2/9/13
to django-res...@googlegroups.com
Matt

Thanks for the reply back with a detailed breakdown of each item you had concerns about. I think the biggest difference is that first point you mentioned - normal django apps throw a 403 without a valid csrf token in the header or form data when you do an HTTP Post (even if you are anonymous / not logged in)

Thanks again to Tom for letting me throw down in such a public way and getting back with such detail. One last item that would help me close this issue down - Tom can you make that github repo public and link to it here so if others have concerns they have an example to see it in action?

Alex G Rothberg

unread,
Feb 25, 2015, 10:27:49 PM2/25/15
to django-res...@googlegroups.com
What are the cases when I have to decorate my views then with ensure_csrf_cookie? I have a SPA that uses DRF for the backend. I had been decorating the one HTML page with that decorator but now I realize that it might not be needed at all.
Reply all
Reply to author
Forward
0 new messages