mirror of https://github.com/django/django.git
Fixed #32817 -- Added the token source to CsrfViewMiddleware's bad token error messages.
This commit is contained in:
parent
1a284afb07
commit
fcb75651f9
|
@ -11,6 +11,7 @@ from urllib.parse import urlparse
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import DisallowedHost, ImproperlyConfigured
|
from django.core.exceptions import DisallowedHost, ImproperlyConfigured
|
||||||
|
from django.http.request import HttpHeaders
|
||||||
from django.urls import get_callable
|
from django.urls import get_callable
|
||||||
from django.utils.cache import patch_vary_headers
|
from django.utils.cache import patch_vary_headers
|
||||||
from django.utils.crypto import constant_time_compare, get_random_string
|
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_NO_REFERER = "Referer checking failed - no Referer."
|
||||||
REASON_BAD_REFERER = "Referer checking failed - %s does not match any trusted origins."
|
REASON_BAD_REFERER = "Referer checking failed - %s does not match any trusted origins."
|
||||||
REASON_NO_CSRF_COOKIE = "CSRF cookie not set."
|
REASON_NO_CSRF_COOKIE = "CSRF cookie not set."
|
||||||
REASON_CSRF_TOKEN_INCORRECT = 'CSRF token incorrect.'
|
|
||||||
REASON_CSRF_TOKEN_MISSING = 'CSRF token missing.'
|
REASON_CSRF_TOKEN_MISSING = 'CSRF token missing.'
|
||||||
REASON_MALFORMED_REFERER = "Referer checking failed - Referer is malformed."
|
REASON_MALFORMED_REFERER = "Referer checking failed - Referer is malformed."
|
||||||
REASON_INSECURE_REFERER = "Referer checking failed - Referer is insecure while host is secure."
|
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):
|
if not is_same_domain(referer.netloc, good_referer):
|
||||||
raise RejectRequest(REASON_BAD_REFERER % referer.geturl())
|
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):
|
def _check_token(self, request):
|
||||||
# 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
|
||||||
|
@ -349,14 +356,19 @@ class CsrfViewMiddleware(MiddlewareMixin):
|
||||||
request_csrf_token = request.META[settings.CSRF_HEADER_NAME]
|
request_csrf_token = request.META[settings.CSRF_HEADER_NAME]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise RejectRequest(REASON_CSRF_TOKEN_MISSING)
|
raise RejectRequest(REASON_CSRF_TOKEN_MISSING)
|
||||||
|
token_source = settings.CSRF_HEADER_NAME
|
||||||
|
else:
|
||||||
|
token_source = 'POST'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
request_csrf_token = _sanitize_token(request_csrf_token)
|
request_csrf_token = _sanitize_token(request_csrf_token)
|
||||||
except InvalidTokenFormat as exc:
|
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):
|
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):
|
def process_request(self, request):
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -147,12 +147,24 @@ class CsrfViewMiddlewareTestMixin:
|
||||||
"""
|
"""
|
||||||
cases = [
|
cases = [
|
||||||
(None, None, REASON_CSRF_TOKEN_MISSING),
|
(None, None, REASON_CSRF_TOKEN_MISSING),
|
||||||
(16 * 'a', None, 'CSRF token has incorrect length.'),
|
(16 * 'a', None, 'CSRF token from POST has incorrect length.'),
|
||||||
(64 * '*', None, 'CSRF token has invalid characters.'),
|
(64 * '*', None, 'CSRF token from POST has invalid characters.'),
|
||||||
(64 * 'a', None, 'CSRF token incorrect.'),
|
(64 * 'a', None, 'CSRF token from POST incorrect.'),
|
||||||
(None, 16 * 'a', 'CSRF token has incorrect length.'),
|
(
|
||||||
(None, 64 * '*', 'CSRF token has invalid characters.'),
|
None,
|
||||||
(None, 64 * 'a', 'CSRF token incorrect.'),
|
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:
|
for post_token, meta_token, expected in cases:
|
||||||
with self.subTest(post_token=post_token, meta_token=meta_token):
|
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
|
If a CSRF cookie is present and an invalid token is passed via a
|
||||||
custom CSRF_HEADER_NAME, the middleware rejects the incoming request.
|
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(
|
self._check_bad_or_missing_token(
|
||||||
expected,
|
expected,
|
||||||
meta_token=16 * 'a',
|
meta_token=16 * 'a',
|
||||||
|
|
Loading…
Reference in New Issue