Removed Django 1.1 fallback for CSRF checks.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@15948 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
4550f95f29
commit
21ef64e34c
|
@ -34,7 +34,6 @@ _MAX_CSRF_KEY = 18446744073709551616L # 2 << 63
|
||||||
|
|
||||||
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 %s."
|
REASON_BAD_REFERER = "Referer checking failed - %s does not match %s."
|
||||||
REASON_NO_COOKIE = "No CSRF or session cookie."
|
|
||||||
REASON_NO_CSRF_COOKIE = "CSRF cookie not set."
|
REASON_NO_CSRF_COOKIE = "CSRF cookie not set."
|
||||||
REASON_BAD_TOKEN = "CSRF token missing or incorrect."
|
REASON_BAD_TOKEN = "CSRF token missing or incorrect."
|
||||||
|
|
||||||
|
@ -105,22 +104,14 @@ class CsrfViewMiddleware(object):
|
||||||
if getattr(request, 'csrf_processing_done', False):
|
if getattr(request, 'csrf_processing_done', False):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# If the user doesn't have a CSRF cookie, generate one and store it in the
|
|
||||||
# request, so it's available to the view. We'll store it in a cookie when
|
|
||||||
# we reach the response.
|
|
||||||
try:
|
try:
|
||||||
# In case of cookies from untrusted sources, we strip anything
|
csrf_token = _sanitize_token(request.COOKIES[settings.CSRF_COOKIE_NAME])
|
||||||
# dangerous at this point, so that the cookie + token will have the
|
# Use same token next time
|
||||||
# same, sanitized value.
|
request.META['CSRF_COOKIE'] = csrf_token
|
||||||
request.META["CSRF_COOKIE"] = _sanitize_token(request.COOKIES[settings.CSRF_COOKIE_NAME])
|
|
||||||
cookie_is_new = False
|
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# No cookie, so create one. This will be sent with the next
|
csrf_token = None
|
||||||
# response.
|
# Generate token and store it in the request, so it's available to the view.
|
||||||
request.META["CSRF_COOKIE"] = _get_new_csrf_key()
|
request.META["CSRF_COOKIE"] = _get_new_csrf_key()
|
||||||
# Set a flag to allow us to fall back and allow the session id in
|
|
||||||
# place of a CSRF cookie for this request only.
|
|
||||||
cookie_is_new = True
|
|
||||||
|
|
||||||
# Wait until request.META["CSRF_COOKIE"] has been manipulated before
|
# Wait until request.META["CSRF_COOKIE"] has been manipulated before
|
||||||
# bailing out, so that get_token still works
|
# bailing out, so that get_token still works
|
||||||
|
@ -173,27 +164,17 @@ class CsrfViewMiddleware(object):
|
||||||
)
|
)
|
||||||
return self._reject(request, reason)
|
return self._reject(request, reason)
|
||||||
|
|
||||||
# If the user didn't already have a CSRF cookie, then fall back to
|
if csrf_token is None:
|
||||||
# the Django 1.1 method (hash of session ID), so a request is not
|
# No CSRF cookie. For POST requests, we insist on a CSRF cookie,
|
||||||
# rejected if the form was sent to the user before upgrading to the
|
# and in this way we can avoid all CSRF attacks, including login
|
||||||
# Django 1.2 method (session independent nonce)
|
# CSRF.
|
||||||
if cookie_is_new:
|
logger.warning('Forbidden (%s): %s' % (REASON_NO_CSRF_COOKIE, request.path),
|
||||||
try:
|
extra={
|
||||||
session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
|
'status_code': 403,
|
||||||
csrf_token = _make_legacy_session_token(session_id)
|
'request': request,
|
||||||
except KeyError:
|
}
|
||||||
# No CSRF cookie and no session cookie. For POST requests,
|
)
|
||||||
# we insist on a CSRF cookie, and in this way we can avoid
|
return self._reject(request, REASON_NO_CSRF_COOKIE)
|
||||||
# all CSRF attacks, including login CSRF.
|
|
||||||
logger.warning('Forbidden (%s): %s' % (REASON_NO_COOKIE, request.path),
|
|
||||||
extra={
|
|
||||||
'status_code': 403,
|
|
||||||
'request': request,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return self._reject(request, REASON_NO_COOKIE)
|
|
||||||
else:
|
|
||||||
csrf_token = request.META["CSRF_COOKIE"]
|
|
||||||
|
|
||||||
# check incoming token
|
# check incoming token
|
||||||
request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
|
request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
|
||||||
|
@ -202,23 +183,13 @@ class CsrfViewMiddleware(object):
|
||||||
request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '')
|
request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '')
|
||||||
|
|
||||||
if not constant_time_compare(request_csrf_token, csrf_token):
|
if not constant_time_compare(request_csrf_token, csrf_token):
|
||||||
if cookie_is_new:
|
logger.warning('Forbidden (%s): %s' % (REASON_BAD_TOKEN, request.path),
|
||||||
# probably a problem setting the CSRF cookie
|
extra={
|
||||||
logger.warning('Forbidden (%s): %s' % (REASON_NO_CSRF_COOKIE, request.path),
|
'status_code': 403,
|
||||||
extra={
|
'request': request,
|
||||||
'status_code': 403,
|
}
|
||||||
'request': request,
|
)
|
||||||
}
|
return self._reject(request, REASON_BAD_TOKEN)
|
||||||
)
|
|
||||||
return self._reject(request, REASON_NO_CSRF_COOKIE)
|
|
||||||
else:
|
|
||||||
logger.warning('Forbidden (%s): %s' % (REASON_BAD_TOKEN, request.path),
|
|
||||||
extra={
|
|
||||||
'status_code': 403,
|
|
||||||
'request': request,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return self._reject(request, REASON_BAD_TOKEN)
|
|
||||||
|
|
||||||
return self._accept(request)
|
return self._accept(request)
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,6 @@ from django.http import HttpRequest, HttpResponse
|
||||||
from django.middleware.csrf import CsrfMiddleware, CsrfViewMiddleware
|
from django.middleware.csrf import CsrfMiddleware, CsrfViewMiddleware
|
||||||
from django.views.decorators.csrf import csrf_exempt, csrf_view_exempt, requires_csrf_token
|
from django.views.decorators.csrf import csrf_exempt, csrf_view_exempt, requires_csrf_token
|
||||||
from django.core.context_processors import csrf
|
from django.core.context_processors import csrf
|
||||||
from django.contrib.sessions.middleware import SessionMiddleware
|
|
||||||
from django.utils.importlib import import_module
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.template import RequestContext, Template
|
from django.template import RequestContext, Template
|
||||||
|
|
||||||
|
@ -62,14 +60,6 @@ class CsrfMiddlewareTest(TestCase):
|
||||||
_csrf_id_cookie = "<1>\xc2\xa1"
|
_csrf_id_cookie = "<1>\xc2\xa1"
|
||||||
_csrf_id = "1"
|
_csrf_id = "1"
|
||||||
|
|
||||||
# This is a valid session token for this ID and secret key. This was generated using
|
|
||||||
# the old code that we're to be backwards-compatible with. Don't use the CSRF code
|
|
||||||
# to generate this hash, or we're merely testing the code against itself and not
|
|
||||||
# checking backwards-compatibility. This is also the output of (echo -n test1 | md5sum).
|
|
||||||
_session_token = "5a105e8b9d40e1329780d62ea2265d8a"
|
|
||||||
_session_id = "1"
|
|
||||||
_secret_key_for_session_test= "test"
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.save_warnings_state()
|
self.save_warnings_state()
|
||||||
warnings.filterwarnings('ignore', category=DeprecationWarning,
|
warnings.filterwarnings('ignore', category=DeprecationWarning,
|
||||||
|
@ -101,17 +91,6 @@ class CsrfMiddlewareTest(TestCase):
|
||||||
req.POST['csrfmiddlewaretoken'] = self._csrf_id
|
req.POST['csrfmiddlewaretoken'] = self._csrf_id
|
||||||
return req
|
return req
|
||||||
|
|
||||||
def _get_POST_session_request_with_token(self):
|
|
||||||
req = self._get_POST_no_csrf_cookie_request()
|
|
||||||
req.COOKIES[settings.SESSION_COOKIE_NAME] = self._session_id
|
|
||||||
req.POST['csrfmiddlewaretoken'] = self._session_token
|
|
||||||
return req
|
|
||||||
|
|
||||||
def _get_POST_session_request_no_token(self):
|
|
||||||
req = self._get_POST_no_csrf_cookie_request()
|
|
||||||
req.COOKIES[settings.SESSION_COOKIE_NAME] = self._session_id
|
|
||||||
return req
|
|
||||||
|
|
||||||
def _check_token_present(self, response, csrf_id=None):
|
def _check_token_present(self, response, csrf_id=None):
|
||||||
self.assertContains(response, "name='csrfmiddlewaretoken' value='%s'" % (csrf_id or self._csrf_id))
|
self.assertContains(response, "name='csrfmiddlewaretoken' value='%s'" % (csrf_id or self._csrf_id))
|
||||||
|
|
||||||
|
@ -226,10 +205,10 @@ class CsrfMiddlewareTest(TestCase):
|
||||||
self.assertEqual(resp_content, resp2.content)
|
self.assertEqual(resp_content, resp2.content)
|
||||||
|
|
||||||
# Check the request processing
|
# Check the request processing
|
||||||
def test_process_request_no_session_no_csrf_cookie(self):
|
def test_process_request_no_csrf_cookie(self):
|
||||||
"""
|
"""
|
||||||
Check that if neither a CSRF cookie nor a session cookie are present,
|
Check that if no CSRF cookies is present, the middleware rejects the
|
||||||
the middleware rejects the incoming request. This will stop login CSRF.
|
incoming request. This will stop login CSRF.
|
||||||
"""
|
"""
|
||||||
req = self._get_POST_no_csrf_cookie_request()
|
req = self._get_POST_no_csrf_cookie_request()
|
||||||
req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
|
req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
|
||||||
|
@ -252,29 +231,6 @@ class CsrfMiddlewareTest(TestCase):
|
||||||
req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
|
req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
|
||||||
self.assertEqual(None, req2)
|
self.assertEqual(None, req2)
|
||||||
|
|
||||||
def test_process_request_session_cookie_no_csrf_cookie_token(self):
|
|
||||||
"""
|
|
||||||
When no CSRF cookie exists, but the user has a session, check that a token
|
|
||||||
using the session cookie as a legacy CSRF cookie is accepted.
|
|
||||||
"""
|
|
||||||
orig_secret_key = settings.SECRET_KEY
|
|
||||||
settings.SECRET_KEY = self._secret_key_for_session_test
|
|
||||||
try:
|
|
||||||
req = self._get_POST_session_request_with_token()
|
|
||||||
req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
|
|
||||||
self.assertEqual(None, req2)
|
|
||||||
finally:
|
|
||||||
settings.SECRET_KEY = orig_secret_key
|
|
||||||
|
|
||||||
def test_process_request_session_cookie_no_csrf_cookie_no_token(self):
|
|
||||||
"""
|
|
||||||
Check that if a session cookie is present but no token and no CSRF cookie,
|
|
||||||
the request is rejected.
|
|
||||||
"""
|
|
||||||
req = self._get_POST_session_request_no_token()
|
|
||||||
req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
|
|
||||||
self.assertEqual(403, req2.status_code)
|
|
||||||
|
|
||||||
def test_process_request_csrf_cookie_no_token_exempt_view(self):
|
def test_process_request_csrf_cookie_no_token_exempt_view(self):
|
||||||
"""
|
"""
|
||||||
Check that if a CSRF cookie is present and no token, but the csrf_exempt
|
Check that if a CSRF cookie is present and no token, but the csrf_exempt
|
||||||
|
|
Loading…
Reference in New Issue