summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Jerdonek <chris.jerdonek@gmail.com>2021-06-08 09:33:26 -0700
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2021-06-23 16:07:15 +0200
commitfcb75651f9b8c2f76ec037f1a68a0e5c99263d8c (patch)
tree69f1a1eb96de04d84070dbfbfda70166d7b4f398
parent1a284afb07ad8806b29044a8cdd0d0bb20165fa4 (diff)
Fixed #32817 -- Added the token source to CsrfViewMiddleware's bad token error messages.
-rw-r--r--django/middleware/csrf.py18
-rw-r--r--tests/csrf_tests/tests.py29
2 files changed, 37 insertions, 10 deletions
diff --git a/django/middleware/csrf.py b/django/middleware/csrf.py
index ca32a040f4..c2a9470ab1 100644
--- a/django/middleware/csrf.py
+++ b/django/middleware/csrf.py
@@ -11,6 +11,7 @@ from urllib.parse import urlparse
from django.conf import settings
from django.core.exceptions import DisallowedHost, ImproperlyConfigured
+from django.http.request import HttpHeaders
from django.urls import get_callable
from django.utils.cache import patch_vary_headers
from django.utils.crypto import constant_time_compare, get_random_string
@@ -28,7 +29,6 @@ REASON_BAD_ORIGIN = "Origin checking failed - %s does not match any trusted orig
REASON_NO_REFERER = "Referer checking failed - no Referer."
REASON_BAD_REFERER = "Referer checking failed - %s does not match any trusted origins."
REASON_NO_CSRF_COOKIE = "CSRF cookie not set."
-REASON_CSRF_TOKEN_INCORRECT = 'CSRF token incorrect.'
REASON_CSRF_TOKEN_MISSING = 'CSRF token missing.'
REASON_MALFORMED_REFERER = "Referer checking failed - Referer is malformed."
REASON_INSECURE_REFERER = "Referer checking failed - Referer is insecure while host is secure."
@@ -315,6 +315,13 @@ class CsrfViewMiddleware(MiddlewareMixin):
if not is_same_domain(referer.netloc, good_referer):
raise RejectRequest(REASON_BAD_REFERER % referer.geturl())
+ def _bad_token_message(self, reason, token_source):
+ if token_source != 'POST':
+ # Assume it is a settings.CSRF_HEADER_NAME value.
+ header_name = HttpHeaders.parse_header_name(token_source)
+ token_source = f'the {header_name!r} HTTP header'
+ return f'CSRF token from {token_source} {reason}.'
+
def _check_token(self, request):
# Access csrf_token via self._get_token() as rotate_token() may have
# been called by an authentication middleware during the
@@ -349,14 +356,19 @@ class CsrfViewMiddleware(MiddlewareMixin):
request_csrf_token = request.META[settings.CSRF_HEADER_NAME]
except KeyError:
raise RejectRequest(REASON_CSRF_TOKEN_MISSING)
+ token_source = settings.CSRF_HEADER_NAME
+ else:
+ token_source = 'POST'
try:
request_csrf_token = _sanitize_token(request_csrf_token)
except InvalidTokenFormat as exc:
- raise RejectRequest(f'CSRF token {exc.reason}.')
+ reason = self._bad_token_message(exc.reason, token_source)
+ raise RejectRequest(reason)
if not _compare_masked_tokens(request_csrf_token, csrf_token):
- raise RejectRequest(REASON_CSRF_TOKEN_INCORRECT)
+ reason = self._bad_token_message('incorrect', token_source)
+ raise RejectRequest(reason)
def process_request(self, request):
try:
diff --git a/tests/csrf_tests/tests.py b/tests/csrf_tests/tests.py
index a028b56d08..9f9d380bb3 100644
--- a/tests/csrf_tests/tests.py
+++ b/tests/csrf_tests/tests.py
@@ -147,12 +147,24 @@ class CsrfViewMiddlewareTestMixin:
"""
cases = [
(None, None, REASON_CSRF_TOKEN_MISSING),
- (16 * 'a', None, 'CSRF token has incorrect length.'),
- (64 * '*', None, 'CSRF token has invalid characters.'),
- (64 * 'a', None, 'CSRF token incorrect.'),
- (None, 16 * 'a', 'CSRF token has incorrect length.'),
- (None, 64 * '*', 'CSRF token has invalid characters.'),
- (None, 64 * 'a', 'CSRF token incorrect.'),
+ (16 * 'a', None, 'CSRF token from POST has incorrect length.'),
+ (64 * '*', None, 'CSRF token from POST has invalid characters.'),
+ (64 * 'a', None, 'CSRF token from POST incorrect.'),
+ (
+ None,
+ 16 * 'a',
+ "CSRF token from the 'X-Csrftoken' HTTP header has incorrect length.",
+ ),
+ (
+ None,
+ 64 * '*',
+ "CSRF token from the 'X-Csrftoken' HTTP header has invalid characters.",
+ ),
+ (
+ None,
+ 64 * 'a',
+ "CSRF token from the 'X-Csrftoken' HTTP header incorrect.",
+ ),
]
for post_token, meta_token, expected in cases:
with self.subTest(post_token=post_token, meta_token=meta_token):
@@ -168,7 +180,10 @@ class CsrfViewMiddlewareTestMixin:
If a CSRF cookie is present and an invalid token is passed via a
custom CSRF_HEADER_NAME, the middleware rejects the incoming request.
"""
- expected = 'CSRF token has incorrect length.'
+ expected = (
+ "CSRF token from the 'X-Csrftoken-Customized' HTTP header has "
+ "incorrect length."
+ )
self._check_bad_or_missing_token(
expected,
meta_token=16 * 'a',