1

According to my understanding, the way Django verifies CSRF is by comparing the

request.POST.get('csrfmiddlewaretoken', '') | request.META.get(settings.CSRF_HEADER_NAME, '') == request.session.get(CSRF_SESSION_KEY) | request.COOKIES[settings.CSRF_COOKIE_NAME]

CsrfViewMiddleware

Now the way, these 2 tokens (one from LHS and one from RHS) are compared is by the deciphering using following function

_unsalt_cipher_token

The 2 tokens being compared, are different, but are deciphered to the same "secret".

My question is shouldn't Django ensure that they are different ? Whats the purpose of using the 2 different tokens(and the overhead of deciphering them),if not ensuring they are different ?

Jibin
  • 3,054
  • 7
  • 36
  • 51
  • Why would it want to check they are different? – Daniel Roseman Apr 05 '18 at 17:03
  • Why are they making two different tokens in the first place ? Whatever the reason is, shouldn't they ensure it is different ? – Jibin Apr 06 '18 at 08:54
  • 1
    I really can't understand your thinking at all. *Why* should they be different? The whole point is to avoid request forgery, ie ensuring that a POST is a response to a previously-sent GET. So what about that makes you think they need to be different? – Daniel Roseman Apr 06 '18 at 09:03
  • I understand the purpose of CSRF and I do not think it should be different. But it is. I'm trying to understand why ? – Jibin Apr 06 '18 at 09:05

2 Answers2

1

I think the questioner has few different doubts

  1. Why is the token set in the cookie

    This is explained in jd.'s and Mike DeSimone's answers.

    In short to support AJAX posting and avoid any server side state storage

  2. Why is the tokens salted ? This is explained in Jacques Gaudin's answer

    In short to prevent BREACH attack

  3. Why can't we use a single salted token in both the form and cookie ?

    I think that's because if we use the same salted token, then we'll need to store the secret (unsalted token) in the server side.

Jibin
  • 3,054
  • 7
  • 36
  • 51
0

I am no security expert but the documentation states that

In order to protect against BREACH attacks, the token is not simply the secret; a random salt is prepended to the secret and used to scramble it.

You can read more about BREACH on wikipedia.

Giving the unsalted CSRF secret away with each request would expose the server to BREACH attacks, therefore Django gives the salted secret and when it receives the CSRF token, it unsalts it and compare it to the secret to check they match.

Jacques Gaudin
  • 15,779
  • 10
  • 54
  • 75
  • I understand why Django sends a salted secret, what I don't understand is why it does not reject the requests if both the tokens(salted secret) are same. – Jibin Apr 06 '18 at 07:11
  • Sorry I don't understand your question. – Jacques Gaudin Apr 06 '18 at 20:59
  • The CSRF in the form and in the cookie (both salted) are different strings, right ? That is to prevent BREACH attack. But if you take the csrf from the cookie and use it to replace the hidden csrf input field, it still works. Why does Django do not ensure that these 2 csrfs are different ? – Jibin Apr 11 '18 at 11:37
  • No The CSRF in the form and in the cookie are the same. To validate an ajax post you take the crsftoken from the cookie. – Jacques Gaudin Apr 11 '18 at 12:18
  • Are you sure that the CSRF in the form and in the cookie are the same ? Its not for me. Moreover, I looked into Django code and its verifying the CSRF in the form against the CSRF in the cookie. So taking the CSRF from the cookie defeats the purpose. – Jibin Apr 11 '18 at 21:13
  • Sorry, I got confused reading a 2011 post. The cookie and form token are different but resolve to the same secret. This may help: https://stackoverflow.com/a/5628324/1388292. – Jacques Gaudin Apr 12 '18 at 07:35