Opened 6 years ago

Closed 5 years ago

Last modified 5 years ago

#15354 closed Bug (fixed)

Cookie with CSRF token not always available for AJAX Post requests

Reported by: Sayane Owned by: nobody
Component: CSRF Version: master
Severity: Normal Keywords:
Cc: me@…, Chris Lamb Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX:

Description

Quote from mailing list:

There's a problem with CSRF Protection and XHR requests. It works perfectly if 'csrftoken' cookie has been set already. But what if it's not?
Cookie with token will be set only, if META["CSRF_COOKIE_USED"] is True [1]. It's set to True in function get_token() [2]. get_token() is called in CsrfResponseMiddleware [3] (It's deprecated, i'm not using it) and in 'csrf' context processor (note - calling it is lazy, so I need to use {% csrf_token %} or at least get the value of csrf_token variable).

But in my project i'm not using {% csrf_token %} anywhere. According to documentation [5] I'm not required to do anything else, but write a simple javascript code. Actually it's not true. I have to put "request.META['CSRF_COOKIE_USED'] = True" line in every view (or write appropriate decorator).

What is more, it will affect users who didn't come across page where csrf_token is used, but their browser needs to send xhr post request.

It affects svn version. I don't know if other versions are affected.

[1] http://code.djangoproject.com/browser/django/trunk/django/middleware/csrf.py#L236
[2] http://code.djangoproject.com/browser/django/trunk/django/middleware/csrf.py#L67
[3] http://code.djangoproject.com/browser/django/trunk/django/middleware/csrf.py#L270
[4] http://code.djangoproject.com/browser/django/trunk/django/core/context_processors.py#L38
[5] http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax

Attachments (1)

03_add_csrf_ensure_cookie_decorator.diff (844 bytes) - added by Chris Lamb 5 years ago.

Download all attachments as: .zip

Change History (13)

comment:1 Changed 6 years ago by Gabriel Hurley

Component: UncategorizedContrib apps
Needs documentation: unset
Needs tests: unset
Patch needs improvement: unset
Triage Stage: UnreviewedAccepted

comment:2 Changed 6 years ago by Valentin Golev

Maybe there is a need for a setting, like

CSRF_COOKIE_IN_EVERY_RESPONSE = True

comment:3 Changed 6 years ago by Valentin Golev

Cc: me@… added

comment:4 Changed 6 years ago by Gabriel Hurley

Component: Contrib appscontrib.csrf

comment:5 Changed 6 years ago by Łukasz Rekucki

Severity: Normal
Type: Bug

comment:6 Changed 5 years ago by Chris Lamb

Cc: Chris Lamb added
Has patch: set

I can't think of a nice *general* fix that doesn't involve a setting - we really do not want to speculatively set a CSRF cookie on every response (ie. remove the CSRF_COOKIE_USED flag checking) as that adds "Vary: Cookie" everywhere, uses entropy, bloats headers, etc. However, a patch for a setting enabling this for certain projects would be pretty trivial (just check for it in CsrfMiddleware.process_response).

My solution would be add a view decorator that ensures the CSRF cookie is set in the corresponding response. I'm attaching this now - it works well and is better than having to place a {% csrf_token %} inside a HTML comment or some other horrible hack.

Changed 5 years ago by Chris Lamb

comment:7 Changed 5 years ago by Aymeric Augustin

Easy pickings: unset

#15925 was a duplicate.

comment:8 Changed 5 years ago by Luke Plant

I'm not going to use the patch here because it will only work if the middleware is enabled, and a function named ensure_csrf_cookie is going to be less surprising if it doesn't have dependencies like that. I will close with a different implementation of ensure_csrf_cookie soon.

comment:9 Changed 5 years ago by Luke Plant

Resolution: fixed
Status: newclosed

In [16192]:

Fixed #15354 - provide method to ensure CSRF token is always available for AJAX requests

Thanks to sayane for the report.

comment:10 Changed 5 years ago by anonymous

Couldn't you just use:

from django.middleware.csrf import get_token

def some_view(request):

get_token(request)

seems simpler than a decorator.

comment:11 in reply to:  10 Changed 5 years ago by Luke Plant

Replying to anonymous:

Couldn't you just use...

This will only work if the CSRF middleware is installed, ensure_csrf_cookie works in either case.

comment:12 Changed 5 years ago by Jacob

milestone: 1.3

Milestone 1.3 deleted

Note: See TracTickets for help on using tickets.
Back to Top