Opened 4 years ago

Closed 4 years ago

Last modified 3 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@…, lamby 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 lamby 4 years ago.

Download all attachments as: .zip

Change History (13)

comment:1 Changed 4 years ago by gabrielhurley

  • Component changed from Uncategorized to Contrib apps
  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Accepted

comment:2 Changed 4 years ago by valyagolev

Maybe there is a need for a setting, like

CSRF_COOKIE_IN_EVERY_RESPONSE = True

comment:3 Changed 4 years ago by valyagolev

  • Cc me@… added

comment:4 Changed 4 years ago by gabrielhurley

  • Component changed from Contrib apps to contrib.csrf

comment:5 Changed 4 years ago by lrekucki

  • Severity set to Normal
  • Type set to Bug

comment:6 Changed 4 years ago by lamby

  • Cc lamby 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 4 years ago by lamby

comment:7 Changed 4 years ago by aaugustin

  • Easy pickings unset

#15925 was a duplicate.

comment:8 Changed 4 years ago by lukeplant

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 4 years ago by lukeplant

  • Resolution set to fixed
  • Status changed from new to closed

In [16192]:

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

Thanks to sayane for the report.

comment:10 follow-up: Changed 4 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 4 years ago by lukeplant

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 3 years ago by jacob

  • milestone 1.3 deleted

Milestone 1.3 deleted

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