Fixed #32796 -- Changed CsrfViewMiddleware to fail earlier on badly formatted cookie tokens.

This commit is contained in:
Chris Jerdonek 2021-05-31 04:26:11 -07:00 committed by Mariusz Felisiak
parent 623cec0879
commit cd19db10df
2 changed files with 17 additions and 10 deletions

View File

@ -217,14 +217,12 @@ class CsrfViewMiddleware(MiddlewareMixin):
except KeyError: except KeyError:
return None return None
try: # This can raise InvalidTokenFormat.
csrf_token = _sanitize_token(cookie_token) csrf_token = _sanitize_token(cookie_token)
except InvalidTokenFormat:
csrf_token = _get_new_csrf_token()
if csrf_token != cookie_token: if csrf_token != cookie_token:
# Cookie token needed to be replaced; # Then the cookie token had length CSRF_SECRET_LENGTH, so flag
# the cookie needs to be reset. # to replace it with the masked version.
request.csrf_cookie_needs_reset = True request.csrf_cookie_needs_reset = True
return csrf_token return csrf_token
@ -318,7 +316,12 @@ class CsrfViewMiddleware(MiddlewareMixin):
raise RejectRequest(REASON_BAD_REFERER % referer.geturl()) raise RejectRequest(REASON_BAD_REFERER % referer.geturl())
def process_request(self, request): def process_request(self, request):
try:
csrf_token = self._get_token(request) csrf_token = self._get_token(request)
except InvalidTokenFormat:
csrf_token = _get_new_csrf_token()
request.csrf_cookie_needs_reset = True
if csrf_token is not None: if csrf_token is not None:
# Use same token next time. # Use same token next time.
request.META['CSRF_COOKIE'] = csrf_token request.META['CSRF_COOKIE'] = csrf_token
@ -374,7 +377,11 @@ class CsrfViewMiddleware(MiddlewareMixin):
# Access csrf_token via self._get_token() as rotate_token() may have # Access csrf_token via self._get_token() as rotate_token() may have
# been called by an authentication middleware during the # been called by an authentication middleware during the
# process_request() phase. # process_request() phase.
try:
csrf_token = self._get_token(request) csrf_token = self._get_token(request)
except InvalidTokenFormat as exc:
return self._reject(request, f'CSRF cookie {exc.reason}.')
if csrf_token is None: if csrf_token is None:
# No CSRF cookie. For POST requests, we insist on a CSRF cookie, # No CSRF cookie. For POST requests, we insist on a CSRF cookie,
# and in this way we can avoid all CSRF attacks, including login # and in this way we can avoid all CSRF attacks, including login

View File

@ -863,14 +863,14 @@ class CsrfViewMiddlewareTests(CsrfViewMiddlewareTestMixin, SimpleTestCase):
If the CSRF cookie has invalid characters in a POST request, the If the CSRF cookie has invalid characters in a POST request, the
middleware rejects the incoming request. middleware rejects the incoming request.
""" """
self._check_bad_or_missing_cookie(64 * '*', REASON_CSRF_TOKEN_MISSING) self._check_bad_or_missing_cookie(64 * '*', 'CSRF cookie has invalid characters.')
def test_bad_csrf_cookie_length(self): def test_bad_csrf_cookie_length(self):
""" """
If the CSRF cookie has an incorrect length in a POST request, the If the CSRF cookie has an incorrect length in a POST request, the
middleware rejects the incoming request. middleware rejects the incoming request.
""" """
self._check_bad_or_missing_cookie(16 * 'a', REASON_CSRF_TOKEN_MISSING) self._check_bad_or_missing_cookie(16 * 'a', 'CSRF cookie has incorrect length.')
def test_process_view_token_too_long(self): def test_process_view_token_too_long(self):
""" """