Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django 1.6 HTTP_X_CSRFTOKEN header ignored if csrf cookie is missing

I have AJAX code which makes POST requests to a Django 1.6.4 application. The view has CSRF protection enabled via the django.middleware.csrf.CsrfViewMiddleware. If I do not pass a cookie but do pass the HTTP_X_CSRFTOKEN, it fails.

I am looking at the code of django.middleware.csrf.CsrfViewMiddleware and I see that on line 161 it checks to see if if csrf_token is None: after getting it from the cookie. If it is None, it returns. Only afterwards does it check the csrfmiddlewaretoken param and the HTTP_X_CSRFTOKEN request header. This looks incorrect and the check for a missing csrf_token value should only be made after checking all the possible places for where it could be found.

Any one else had similar issues? Am I seeing this incorrectly?

like image 439
Krystian Cybulski Avatar asked Oct 21 '25 04:10

Krystian Cybulski


2 Answers

I think the confusion might be that the CSRF cookie and the HTTP_X_CSRFTOKEN HTTP header exist on opposite sides of the comparison. In other words, to prevent CSRF attacks, Django compares:

CSRF cookie value vs. POST token value ("csrfmiddlewaretoken")

(or)

CSRF cookie value vs. HTTP header value ("HTTP_X_CSRFTOKEN")

That's why the cookie is always necessary. Using the HTTP_X_CSRFTOKEN header is a substitute for setting the token in POST data, not a substitute for the cookie.

like image 197
SMX Avatar answered Oct 23 '25 18:10

SMX


If you are using jQuery you can create a beforeSend function that includes the csrf token. Django CSRF for more information.

Please be aware that Django looks for the Header X-CSRFToken not HTTP_X_CSRFTOKEN. At least that was my problem during debugging of the code. (I also checked the django.middleware.csrf.CsrfViewMiddleware for this)


The if csrf_token is None is a extra check done by Django. (Stated from the comment in the if-statement.

No CSRF cookie. For POST requests, we insist on a CSRF cookie, and in this way we can avoid all CSRF attacks, including login CSRF.

I think (not sure) there is no single check to only validate the header from a ajax post request, and Django will do checks to prevent any form of CSRF attacks.

like image 43
Eagllus Avatar answered Oct 23 '25 20:10

Eagllus