Trying to learn about security. Curious about why in django when submitting a form (a POST), there are 2 separate "elements" that contain the same csrf token value:
- the csrftoken cookie: COOKIES:{'csrftoken': '1effe96056e91a8f58461ad56c0d4ddc', ... - the Form's hidden csrfmiddlewaretoken: POST:<QueryDict: {u'csrfmiddlewaretoken': [u'1effe96056e91a8f58461ad56c0d4ddc'], ...
If django is inserting the hidden csrf field/value to the form when it sends it to the browser (GET), and expects the same value back when receiving the POST, then why is it necessary to also set a cookie?
A more general question, if either of them was missing (form, cookie), could you provide a scenario that explains how this could be exploited (security attack)?
By the way, I ran a couple of simple tests to make sure that django was checking the validity of each one separately and indeed it is:
if I change the form's csrf value before doing the POST, I get this debug error back:
CSRF token missing or incorrect
if I delete the csrf cookie before doing the POST, I get a different error back:
CSRF cookie not set.
I'm just familiar with basic csrf concepts and want to learn how django helps protect against these types of attacks.
Thanks,
jd
update:
Although both answers (S.Lott and M. DeSimone) were informative and make sense, I thought that there could be a more detailed explanation for requiring the presence of the security value in both the form and in the cookie. While searching outside stackoverflow.com, I came across a blog post from...Jeff Atwood.
I have included a third answer (sorry to answer my own question but I think that it is relevant supplemental info) that refers to a blog post from Jeff and includes a quotation.
CSRF tokens prevent CSRF because without token, attacker cannot create a valid requests to the backend server. For the Synchronised Token Pattern, CSRF tokens should not be transmitted using cookies. The CSRF token can be transmitted to the client as part of a response payload, such as a HTML or JSON response.
Django has a {% csrf_token %} tag that is implemented to avoid malicious attacks. It generates a token on the server-side when rendering the page and makes sure to cross-check this token for any requests coming back in. If the incoming requests do not contain the token, they are not executed.
For all incoming requests that are not using HTTP GET, HEAD, OPTIONS or TRACE, a CSRF cookie must be present, and the 'csrfmiddlewaretoken' field must be present and correct. If it isn't, the user will get a 403 error.
From Jeff Atwood's blog entry:
Preventing CSRF and XSRF Attacks (Oct 14, 2008)
The original post
The Felten and Zeller paper (pdf) recommends the "double-submitted cookie" method to prevent XSRF:
When a user visits a site, the site should generate a (cryptographically strong) pseudorandom value and set it as a cookie on the user's machine. The site should require every form submission to include this pseudorandom value as a form value and also as a cookie value. When a POST request is sent to the site, the request should only be considered valid if the form value and the cookie value are the same. When an attacker submits a form on behalf of a user, he can only modify the values of the form. An attacker cannot read any data sent from the server or modify cookie values, per the same-origin policy. This means that while an attacker can send any value he wants with the form, he will be unable to modify or read the value stored in the cookie. Since the cookie value and the form value must be the same, the attacker will be unable to successfully submit a form unless he is able to guess the pseudorandom value.
The advantage of this approach is that it requires no server state; you simply set the cookie value once, then every HTTP POST checks to ensure that one of the submitted values contains the exact same cookie value. Any difference between the two means a possible XSRF attack.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With