Is CSRF middleware to be taken seriously (from a XSRF point of view)?

70 views
Skip to first unread message

Stephan Doliov

unread,
Jan 15, 2018, 5:03:22 PM1/15/18
to Django users
Just curious, I recently went on a source code studying binge and took a look at the CSRF middleware that comes with Django. I appreciate the work and effort of the authors, but I am not sure I gain anything by deploying it to my site. Here is why:
The middleware token assigned to a form and to a csrftoken cookie are ciphertexts of the same underlying key (by default, the underlying key is chosen as 32 randomly chosen (with replacement) chars from a set of 62 chars. So the easy workaround can be done in one of two ways

1) Write a script that just harvests the middleware token from a form "protected" with such token and use the value of that as the csrftoken cookie.
As the middlewaretoken is a cipher of the underlying token, obviously using the the same string as the value to the csrftoken cookie will satisfy the middleware's demand for authorization of the resource (e.g. POSTing to the form)

2) Learn the easy cipher algorithm the csrf middleware uses and present a csrf token cookie that will decode to the right value.

In either case, I am not convinced that meaningful protection against CSRF types of requests are provided by the middleware. Am I missing something?

Wouldn't it be more secure to just have middleware that whitelists as a series of origins (aka CORS) and then, unlike CORS, actually perform reverse lookups on the dns of the whitelisted domains? (Of course, this assumes that the hosts that might want to make cross-site requests ahve access to managing their reverse DNS).

Am I missing something; or, if serving performance is a top goal of mine, should I just ditch the csrf middleware? (and maybe rate limit client requests to prevent DoS attacks)?

Thanks,
Steve

Antonis Christofides

unread,
Jan 16, 2018, 2:13:34 AM1/16/18
to django...@googlegroups.com

Hi,

1) Write a script that just harvests the middleware token from a form "protected" with such token and use the value of that as the csrftoken cookie.

You visit web site A (the attacker). Web site A wants to send a malicious POST request to site D (a Django app). The thing is that scripts of web site A don't have access to forms of site D, so they can't get the csrf token.

2) Learn the easy cipher algorithm the csrf middleware uses and present a csrf token cookie that will decode to the right value.

This is not possible. You can't decode such ciphered messages. If S is the original message and C = F(S) the ciphered message, you can't reverse the function and find S given C.

Regards,

Antonis
Antonis Christofides
http://djangodeployment.com
--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/9c4a794f-aa9e-4c00-ba20-779ad7a87d2a%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

James Bennett

unread,
Jan 16, 2018, 3:35:24 AM1/16/18
to django...@googlegroups.com
The base CSRF secret is per-user, not global. So while you could write a script to hit a page over and over and harvest CSRF tokens, those tokens would only be valid for the session/user associated with your script. Attempting to use them to execute a CSRF attack against another user would fail (since the other user would have a different base CSRF secret, and therefore the tokens you'd harvested would not be valid for that user).

To generate a valid token for another user, you would need to see valid tokens for that user. The only way to do this (assuming a properly-configured site using HTTPS) is to already have compromised that user's account. In which case, it doesn't matter that you can CSRF them, because you've already fully compromised their account.

Etienne Robillard

unread,
Jan 16, 2018, 4:28:27 AM1/16/18
to Stephan Doliov, django...@googlegroups.com, django-...@googlegroups.com

Hi Stephan,

I'm also interested to understand why I should have some form of CSRF protection for my wsgi app...

perhaps recoding the Django 1.11 CSRF middleware into a proper WSGI application (CSRFController) would help.

but seriously, i don't use/recommend the Django CSRF middleware because it does not improve security of forms processing.


cheers,

Etienne

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/9c4a794f-aa9e-4c00-ba20-779ad7a87d2a%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

James Bennett

unread,
Jan 16, 2018, 4:39:58 AM1/16/18
to django...@googlegroups.com, Stephan Doliov, django-...@googlegroups.com
If you can demonstrate a practical attack against Django's CSRF system, feel free to email it to secu...@djangoproject.com.

On Tue, Jan 16, 2018 at 1:26 AM, Etienne Robillard <tka...@yandex.com> wrote:

Hi Stephan,

I'm also interested to understand why I should have some form of CSRF protection for my wsgi app...

perhaps recoding the Django 1.11 CSRF middleware into a proper WSGI application (CSRFController) would help.

but seriously, i don't use/recommend the Django CSRF middleware because it does not improve security of forms processing.


cheers,

Etienne



Le 2018-01-15 à 17:03, Stephan Doliov a écrit :
Just curious, I recently went on a source code studying binge and took a look at the CSRF middleware that comes with Django. I appreciate the work and effort of the authors, but I am not sure I gain anything by deploying it to my site. Here is why:
The middleware token assigned to a form and to a csrftoken cookie are ciphertexts of the same underlying key (by default, the underlying key is chosen as 32 randomly chosen (with replacement) chars from a set of 62 chars. So the easy workaround can be done in one of two ways

1) Write a script that just harvests the middleware token from a form "protected" with such token and use the value of that as the csrftoken cookie.
As the middlewaretoken is a cipher of the underlying token, obviously using the the same string as the value to the csrftoken cookie will satisfy the middleware's demand for authorization of the resource (e.g. POSTing to the form)

2) Learn the easy cipher algorithm the csrf middleware uses and present a csrf token cookie that will decode to the right value.

In either case, I am not convinced that meaningful protection against CSRF types of requests are provided by the middleware. Am I missing something?

Wouldn't it be more secure to just have middleware that whitelists as a series of origins (aka CORS) and then, unlike CORS, actually perform reverse lookups on the dns of the whitelisted domains? (Of course, this assumes that the hosts that might want to make cross-site requests ahve access to managing their reverse DNS).

Am I missing something; or, if serving performance is a top goal of mine, should I just ditch the csrf middleware? (and maybe rate limit client requests to prevent DoS attacks)?

Thanks,
Steve
--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.

To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.

Etienne Robillard

unread,
Jan 16, 2018, 4:49:21 AM1/16/18
to James Bennett, Stephan Doliov, django...@googlegroups.com, django-...@googlegroups.com

A much more practical way to improve security against XSRF attacks is using nginx.

Regards,

Etienne

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

To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.

For more options, visit https://groups.google.com/d/optout.

knbk

unread,
Jan 16, 2018, 10:32:46 AM1/16/18
to Django users
Hi Steve,

First let's get into how cross-site request forgery works: when you are logged in to bank.com, your browser saves a session cookie and sends it with every request. Now when you visit evil.com, they may include a piece of javascript in their side that sends a POST request to bank.com/transfer/ to transfer $1000 from your account into theirs. Your browser executes the javascript, and happily sends a request to bank.com/transfer/ along with the transfer details and your session cookie. The session cookie authenticates the request as coming from you, so the bank has no reason to suspect that you didn't want to transfer the money. The issue here is that your browser sends the session cookie with every request.

Django uses a so-called double submit cookie[1] to protect against CSRF attacks. This is a well-documented pattern for CSRF protection. In addition to the session cookie, a CSRF token cookie is set in the browser. This contains a randomly generated value that is unique to your browser. This value is also included as a form field (or a request header) in any POST request you make. When you send a request, Django checks if the two values are the same. If they are, then that proves (up to a point) that the request is from a party that has legitimate access to the token value. Barring any more extensive attacks (such as cross-site scripting), evil.com has no way to get the correct value of the CSRF token. Javascript executed on evil.com has no access to the cookies for bank.com, and opening a page from bank.com in e.g. an iframe also disallows access to the content of that iframe. Only a legitimate party (i.e. you filling in a form on bank.com) has access to the correct token and can submit the same secret as the one in the CSRF token cookie.

As for the "cipher algorithm", this is actually just a padding algorithm to make the value randomized on each page load, while keeping the secret the same. You are right that anyone can reverse this, but that is not an issue. Randomizing the value prevents a class of attacks that includes BEAST, CRIME and BREACH attacks. These attacks work by injecting a value into the page in close proximity to the CSRF token (i.e. when a page displays a GET parameter) and seeing what effect it has on the compression of that page. If the compressed page becomes shorter, then the injected value likely has some values in common with the CSRF token. This allows for recovery of the secret token byte-by-byte, so that evil.com can bypass the CSRF protection in place. Randomizing the value, even if the original value is easily recovered, prevents this class of attacks entirely.

I hope this gives you a better understanding of how CSRF protection works in Django. If you have any more questions feel free to ask here or on IRC (nick: knbk).

Marten


[1] https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Double_Submit_Cookie

knbk

unread,
Jan 16, 2018, 10:36:55 AM1/16/18
to Django users
How does using nginx protect against CSRF attacks?

Marten
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/CAL13Cg9mhBTD-2CBB46cvv2N6gd0JzHA8g5o%2BgrG5ZrAmb-%3Dgg%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Etienne Robillard

unread,
Jan 16, 2018, 12:19:17 PM1/16/18
to knbk, django...@googlegroups.com, django-...@googlegroups.com

knbk

unread,
Jan 16, 2018, 12:33:53 PM1/16/18
to Django users
That does seem to be a good effort towards CSRF prevention. However, it's currently in draft status, and doesn't provide any protection if not supported by your browser. According to caniuse.com[1], the browsers supporting this feature currently occupy just under 60% of the browser market. About 40% of users would still be vulnerable to CSRF attacks. IMO that's too large a chunk of users to leave unprotected.

When this feature reaches maturity it will likely be a good option to combat CSRF, but right now it doesn't provide adequate protection on its own. Django's CSRF middleware does provide protection for the remaining 40%.

Marten


[1] https://caniuse.com/#search=samesite
Reply all
Reply to author
Forward
0 new messages