📜 ⬆️ ⬇️

Django 1.2 and CSRF

CSRF, or Cross-Site Request Forgery (cross-site request forgery) is perhaps one of the most forgotten vulnerabilities. Developers are usually aware of SQL injection and XSS attacks, but very often they forget about CSRF attacks.

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

However, you should not relax; using CSRF, you can do a lot of dirty tricks, from adding spam links to a user profile to using administrative permissions to remove pages or add backdoors. In general, such attacks allow access to everything that requires your authentication and access rights.
')
But the Django developers are awake. Thanks to them, Django has long been CSRFMiddleware, although it is not very good. But let's first consider how a CSRF attack is done in order to better understand what is being said.


Anatomy of a CSRF attack


The 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, acceptable attacker content.

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 in the form on the site, send. The browser makes the following request (yes, I know that this is an invalid HTTP, but I just want to show the gist):

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

amount=100&recipient=00000001


Next, imagine, I, without completing the session (many people just close the tab or go to another site), go to the malicious site. On it, I see a big “Continue” button; However, not all so simple:

<form action = "http://www.andrewsbank.com/banking/transfer/" method = "POST" >
<input type = "hidden" name = "amount" value = "100" />
<input type = "hidden" name = "recipient" value = "00000002" />
<input type = "submit" value = "" />
</form>


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

This is not a very difficult attack, but the bank is not very good (I would advise Alice to transfer her savings to another bank). But still, I hope this example will be enough to understand what this type of attack is and what they are capable of (in fact, for the first time such attacks were 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 article by Jeff Atwood .


CSRF Protection


So how do you protect against CSRF attacks? The basis is the following principle: it is necessary to check that all requests come from these forms from your site.

This can be done by creating a token for each form (or nonce , as security experts say) tied to a user session, and also by checking the REFERER header. You must bind the token to the session, otherwise the attacking site can make a request to your site and get the token.

If you check the session and see that the token was issued relatively recently, you can state with a sufficient degree of 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 iframe page and show the user only one button, say, “delete”), but still better than nothing.


Django and CSRF


Let's return to the previously mentioned CSRFMiddleware. The version that came in the delivery with Django 1.1 worked like this: it took the resulting HTML, passed it through the regular page in search of all the forms and added <input> to them containing the 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 conduct a successful attack on your site.

There were also other problems. For example, it was necessary to connect SessionMiddleware and it was impossible to activate protection against CSRF for only one application, since Middleware is a global thing.


What has changed?


In Django 1.2, CSRFMiddleware is no longer content with regular games, moreover, they are now no longer there, but many new features have appeared.

New protection now requires you to manually add {% csrf_token %} to all 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, new protection is not required to include globally. There is now a new django.views.decorators.csrf.csrf_protect decorator, which 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 the 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 user session state storage mechanism, like signed cookies, it will work.


disadvantages


Any magical solution has its drawbacks. New protection is also 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 the token and send it to your domain. The obvious solution is to make sure that there are no malware on your subdomains, although it may not be as easy as it seems.

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


Conclusion


CSRF is a complex problem that has not yet been completely solved in Django (and may never be completely). However, as with auto-escaping, the goal is to give a solid base from which to push off. New CSRF protection is a good step forward. Now you just have to start using it!

Source: https://habr.com/ru/post/89184/


All Articles