summaryrefslogtreecommitdiff
path: root/django/middleware/csrf.py
diff options
context:
space:
mode:
authorChris Jerdonek <chris.jerdonek@gmail.com>2021-07-16 10:54:42 -0400
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2021-07-23 07:08:45 +0200
commita2e1f1e2954c8144f2acf83402ed1f55ea9692a4 (patch)
treefba55c6258a1a25f2d306ce2759f79d3899d1061 /django/middleware/csrf.py
parent311401d9a278339795a7ab3f1617c4da9077fdcc (diff)
Fixed #32902 -- Fixed CsrfViewMiddleware.process_response()'s cookie reset logic.
Thanks Florian Apolloner and Shai Berger for reviews.
Diffstat (limited to 'django/middleware/csrf.py')
-rw-r--r--django/middleware/csrf.py30
1 files changed, 20 insertions, 10 deletions
diff --git a/django/middleware/csrf.py b/django/middleware/csrf.py
index c2a9470ab1..d103900bdf 100644
--- a/django/middleware/csrf.py
+++ b/django/middleware/csrf.py
@@ -437,15 +437,25 @@ class CsrfViewMiddleware(MiddlewareMixin):
return self._accept(request)
def process_response(self, request, response):
- if not getattr(request, 'csrf_cookie_needs_reset', False):
- if getattr(response, 'csrf_cookie_set', False):
- return response
-
- if not request.META.get("CSRF_COOKIE_USED", False):
- return response
+ # Send the CSRF cookie whenever the cookie is being used (even if the
+ # client already has it) in order to renew the expiry timer, but only
+ # if it hasn't already been sent during this request-response cycle.
+ # Also, send the cookie no matter what if a reset was requested.
+ if (
+ getattr(request, 'csrf_cookie_needs_reset', False) or (
+ request.META.get('CSRF_COOKIE_USED') and
+ not getattr(response, 'csrf_cookie_set', False)
+ )
+ ):
+ self._set_token(request, response)
+ # Update state to prevent _set_token() from being unnecessarily
+ # called again in process_response() by other instances of
+ # CsrfViewMiddleware. This can happen e.g. when both a decorator
+ # and middleware are used. However, the csrf_cookie_needs_reset
+ # attribute is still respected in subsequent calls e.g. in case
+ # rotate_token() is called in process_response() later by custom
+ # middleware but before those subsequent calls.
+ response.csrf_cookie_set = True
+ request.csrf_cookie_needs_reset = False
- # Set the CSRF cookie even if it's already set, so we renew
- # the expiry timer.
- self._set_token(request, response)
- response.csrf_cookie_set = True
return response