Django 1.2 and CSRF

Original author: Andrew Godwin
  • Transfer
CSRF, or Cross-Site Request Forgery, is perhaps one of the most forgotten vulnerabilities. Developers, as a rule, are aware of SQL injections and XSS attacks, but very often forget about CSRF attacks.

For those who are not in the know: CSRF attack uses the user's browser - open sessions and saved cookies - to send a request with malicious data. They, as such, are not server exploits; they can only affect the data stored on the target site to which the user has access.

However, do not relax; using CSRF, you can do a lot of dirty tricks, from adding spam links to your user profile to using administrative privileges to delete pages or add backdoors. In general, such attacks allow you to gain access to everything that requires your authentication and access rights.

But the Django developers are not asleep. Thanks to them, Django has had CSRFMiddleware for a long time, although not very good. But let's first look at how a CSRF attack is done in order to better understand what is being discussed.


Anatomy of a CSRF attack


A CSRF attack is designed in such a way that it forces the user's browser to send a request (GET or POST, depending on the target) to the attacked site with arbitrary content that is acceptable to the attacker.

For example, imagine an online banking system where there is a form that allows you to make money transfers. I want to send Alice (bank account number 00000001) some money. Fill out the form on the site, send. The browser makes the following request (yes, I know that this is invalid HTTP, but I just want to show the essence): Next, imagine, I’m not ending the session (many people just close the tab or go to another site), I go to the malicious site. On it I see a big “Continue” button; However, not all so simple:

    POST /banking/transfer/ HTTP/1.1
    Host: www.andrewsbank.com

    amount=100&recipient=00000001




    
        
        
        
    


As you can see, this innocuous at first glance button sends 100 conventional units to Mr. Bob (number 00000002).

This is not a very difficult attack, but the bank is not very good either (I would advise Alice to transfer her savings to another bank). But still, I hope this example will be enough to understand what these types of attacks are and what they are capable of (in reality, such attacks were first discovered in banking systems).

The Internet is full of resources dedicated to CSRF attacks; if you want more details, you can start with a Wikipedia article ; there is also a good Jeff Atwood article .


CSRF Protection


So how do you protect yourself from CSRF attacks? It is based on the following principle: it is necessary to verify that all requests come from real forms from your site.

You can do this by creating a token for each form (or nonce , as security experts say), tied to a user session, and also checking the REFERER header. It is mandatory to bind a token to a session, otherwise the attacking site can make a request to your site and receive a token.

If you check the session and see that the token was issued relatively recently, you can say with sufficient confidence that this is a real request from the user. You can never be 100% sure in the field of information security, as new types of attacks constantly appear (for example, a malicious website can load your page in an iframe and show the user only one button, say, “delete”), but still it better than nothing.


Django and CSRF


Back to the previously mentioned CSRFMiddleware. The version that came with Django 1.1 worked like this: it took the resulting HTML, passed through the regular table in search of all forms, and added them to themcontaining a token, which was then checked against the incoming POST request.

Besides the fact that this method is simply not very good, the big problem was that the token was added to absolutely all forms, including those that went to external sites. These external sites, armed with a valid token, could carry out a successful attack on your site.

There were also other problems. For example, you had to connect SessionMiddleware and you could not activate CSRF protection for only one application, since Middleware is a global thing.


What has changed?


In Django 1.2, CSRFMiddleware is now not satisfied with some regulars, moreover, they are no longer there at all, but there are many new features.

The new protection now requires you to manually add {% csrf_token %}to all of your forms that you want to protect. Although this means that you need to remember this when creating each new form, it also means that now you will not send valid tokens to external resources.

In addition, the new protection does not need to be included globally. Now there is a new decorator django.views.decorators.csrf.csrf_protectthat you can use to provide protection for specific views. Of course, now this decorator is used in all Django applications, which means that your admin panel is now protected, even if you forgot to connect CSRFMiddleware.

Also, CSRF protection is now part of the Django core, and not a contrib application, as before. We did this because we believe that protection against CSRF attacks, as well as auto-escaping, should be an integral part of a good web framework.

Finally, the new defense uses its own cookie, instead of relying on jung sessions, so if you use your own mechanism for storing the state of a user session, such as signed cookies, it will work.


disadvantages


Any kind of magical solution has its drawbacks. New protection is no exception.

Firstly, it does not protect you from attacks from subdomains of your site, since your cookie is available from them. They can pull out a token from there and send to your domain. The obvious solution is to make sure that your subdomains do not have malware, although this may not be as simple as it seems.

Secondly, this protection will not work on custom template renderers. If you use them, you will have to manually embed tokens in the HTML. You can use the method for this django.middleware.csrf.get_token().


Conclusion


CSRF is a complex issue that has not yet been fully resolved in Django (and probably never will be). However, as with auto-escaping, the goal is to provide a solid foundation from which to push. New CSRF protection is a good step forward. Now you just have to start using it!

Also popular now: