Opened 9 years ago

Closed 9 years ago

Last modified 9 years ago

#13448 closed (fixed)

CsrfResponseMiddleware breaks the Etag in CommonMiddleware

Reported by: defaultwombat Owned by: nobody
Component: HTTP handling Version: 1.1
Severity: Keywords: csrf etag middleware never_cache
Cc: kanu@… Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


If the CsrfResponseMiddleware.process_response adds the csrf_token field to the content the etag of the response doesn't get updated.

The CommonMiddleware.process_response however only generates a new etag if it doesn't already exist.

So the comparison between HTTP_IF_NONE_MATCH and Etag is based on a wrong etag and might lead to a wrong HttpResponseNotModified.

My problem was that I sometimes got a 403 from the csrf-middleware when i added or changed things in the admin site.

Although I haven't resolved the whole puzzle yet, the main pieces are:

  • When you use a admin form the etag is generated by the never_cache decorator.
  • The csrf middleware adds the csrf_token field to the form
  • If your browser doesn't have the page cached everything is fine
  • When you logout and login again and you get a new session_id
  • If you now use the same admin form again the common middleware doesn't notice any changes beween the HTTP_IF_NONE_MATCH and the etag.
  • So it sends a HttpResponseNotModified which let the browser use the cached version of the page.
  • As the csrf_token in the cached page is based on a different session_id you end up with a 403 when you try to submit the form.

Change History (3)

comment:1 Changed 9 years ago by Karen Tracey

Resolution: fixed
Status: newclosed

I can recreate the problem on 1.1.1, but not on either current trunk nor current 1.1.X SVN branch. In current trunk the CSRF token is session-independent, so the logout/login does not cause a problem. In current 1.1.X, something seems to prevent the not-modified response after the logout/login. The sequence I see is:

Django version 1.1.2 pre-alpha SVN-13035, using settings 'playground1_1.settings'
Development server is running at
Quit the server with CTRL-BREAK.
[30/Apr/2010 10:54:18] "GET /admin/ttt/account/1/ HTTP/1.1" 304 0 --> here we're getting not-modified on re-fetch
[30/Apr/2010 10:54:18] "GET /admin/jsi18n/ HTTP/1.1" 304 0
[30/Apr/2010 10:54:24] "GET /admin/logout/ HTTP/1.1" 304 0 --> logout
[30/Apr/2010 10:54:26] "GET /admin/ HTTP/1.1" 200 1825
[30/Apr/2010 10:54:28] "POST /admin/ HTTP/1.1" 302 0 --> log back in
[30/Apr/2010 10:54:28] "GET /admin/ HTTP/1.1" 200 8713
[30/Apr/2010 10:54:31] "GET /admin/ttt/account/1/ HTTP/1.1" 200 3797 --> refetch now returns page of data, not not-modified
[30/Apr/2010 10:54:31] "GET /admin/jsi18n/ HTTP/1.1" 304 0
[30/Apr/2010 11:01:30] "POST /admin/ttt/account/1/ HTTP/1.1" 302 0 --> and post returns successful redirect
[30/Apr/2010 11:01:31] "GET /admin/ttt/account/ HTTP/1.1" 200 3479

On 1.1.1, the same sequence did produce a problem:

Django version 1.1.1, using settings 'playground1_1.settings'
Development server is running at
Quit the server with CTRL-BREAK.
[30/Apr/2010 10:50:47] "GET /admin/ttt/account/1/ HTTP/1.1" 200 3801 --> initial get
[30/Apr/2010 10:50:47] "GET /admin/jsi18n/ HTTP/1.1" 200 453
[30/Apr/2010 10:50:59] "GET /admin/ttt/account/1/ HTTP/1.1" 304 0 --> refetch returns not-modified
[30/Apr/2010 10:50:59] "GET /admin/jsi18n/ HTTP/1.1" 304 0
[30/Apr/2010 10:51:06] "GET /admin/logout/ HTTP/1.1" 200 1161 --> logout
[30/Apr/2010 10:51:09] "GET /admin/ HTTP/1.1" 200 1825
[30/Apr/2010 10:51:11] "GET /admin/ HTTP/1.1" 304 0
[30/Apr/2010 10:51:14] "POST /admin/ HTTP/1.1" 302 0 --> log back in
[30/Apr/2010 10:51:14] "GET /admin/ HTTP/1.1" 200 8712
[30/Apr/2010 10:51:24] "GET /admin/ttt/account/1/ HTTP/1.1" 304 0 --> refetch here still returns not-modified
[30/Apr/2010 10:51:24] "GET /admin/jsi18n/ HTTP/1.1" 304 0
[30/Apr/2010 10:51:32] "POST /admin/ttt/account/1/ HTTP/1.1" 403 159 --> which causes POST failure

So while I have not tracked down what exactly was changed to fix this in the 1.1.X branch, it does appear to already be fixed there.

comment:2 Changed 9 years ago by Luke Plant

Yep, this is a dupe of #9163 which is fixed in trunk (r11650) and 1.1.X (r11651)

comment:3 Changed 9 years ago by defaultwombat

sorry for bad research. just found it in the svn comments.

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