From 21ef64e34c1c84bd7beb07531694d3f22fc42ffd Mon Sep 17 00:00:00 2001 From: Luke Plant Date: Wed, 30 Mar 2011 17:34:14 +0000 Subject: [PATCH] Removed Django 1.1 fallback for CSRF checks. git-svn-id: http://code.djangoproject.com/svn/django/trunk@15948 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/middleware/csrf.py | 75 +++++++---------------- tests/regressiontests/csrf_tests/tests.py | 50 +-------------- 2 files changed, 26 insertions(+), 99 deletions(-) diff --git a/django/middleware/csrf.py b/django/middleware/csrf.py index 3247358ed5..a16a17427b 100644 --- a/django/middleware/csrf.py +++ b/django/middleware/csrf.py @@ -34,7 +34,6 @@ _MAX_CSRF_KEY = 18446744073709551616L # 2 << 63 REASON_NO_REFERER = "Referer checking failed - no Referer." 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_BAD_TOKEN = "CSRF token missing or incorrect." @@ -105,22 +104,14 @@ class CsrfViewMiddleware(object): if getattr(request, 'csrf_processing_done', False): 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: - # In case of cookies from untrusted sources, we strip anything - # dangerous at this point, so that the cookie + token will have the - # same, sanitized value. - request.META["CSRF_COOKIE"] = _sanitize_token(request.COOKIES[settings.CSRF_COOKIE_NAME]) - cookie_is_new = False + csrf_token = _sanitize_token(request.COOKIES[settings.CSRF_COOKIE_NAME]) + # Use same token next time + request.META['CSRF_COOKIE'] = csrf_token except KeyError: - # No cookie, so create one. This will be sent with the next - # response. + csrf_token = None + # Generate token and store it in the request, so it's available to the view. 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 # bailing out, so that get_token still works @@ -173,27 +164,17 @@ class CsrfViewMiddleware(object): ) return self._reject(request, reason) - # If the user didn't already have a CSRF cookie, then fall back to - # the Django 1.1 method (hash of session ID), so a request is not - # rejected if the form was sent to the user before upgrading to the - # Django 1.2 method (session independent nonce) - if cookie_is_new: - try: - session_id = request.COOKIES[settings.SESSION_COOKIE_NAME] - csrf_token = _make_legacy_session_token(session_id) - 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 - # 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"] + if csrf_token is None: + # No CSRF cookie. For POST requests, we insist on a CSRF cookie, + # and in this way we can avoid all CSRF attacks, including login + # CSRF. + logger.warning('Forbidden (%s): %s' % (REASON_NO_CSRF_COOKIE, request.path), + extra={ + 'status_code': 403, + 'request': request, + } + ) + return self._reject(request, REASON_NO_CSRF_COOKIE) # check incoming token request_csrf_token = request.POST.get('csrfmiddlewaretoken', '') @@ -202,23 +183,13 @@ class CsrfViewMiddleware(object): request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '') if not constant_time_compare(request_csrf_token, csrf_token): - if cookie_is_new: - # probably a problem setting the CSRF cookie - logger.warning('Forbidden (%s): %s' % (REASON_NO_CSRF_COOKIE, request.path), - extra={ - 'status_code': 403, - 'request': request, - } - ) - 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) + 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) diff --git a/tests/regressiontests/csrf_tests/tests.py b/tests/regressiontests/csrf_tests/tests.py index d75adc917b..ba1760aa91 100644 --- a/tests/regressiontests/csrf_tests/tests.py +++ b/tests/regressiontests/csrf_tests/tests.py @@ -6,8 +6,6 @@ from django.http import HttpRequest, HttpResponse from django.middleware.csrf import CsrfMiddleware, CsrfViewMiddleware from django.views.decorators.csrf import csrf_exempt, csrf_view_exempt, requires_csrf_token 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.template import RequestContext, Template @@ -62,14 +60,6 @@ class CsrfMiddlewareTest(TestCase): _csrf_id_cookie = "<1>\xc2\xa1" _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): self.save_warnings_state() warnings.filterwarnings('ignore', category=DeprecationWarning, @@ -101,17 +91,6 @@ class CsrfMiddlewareTest(TestCase): req.POST['csrfmiddlewaretoken'] = self._csrf_id 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): 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) # 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, - the middleware rejects the incoming request. This will stop login CSRF. + Check that if no CSRF cookies is present, the middleware rejects the + incoming request. This will stop login CSRF. """ req = self._get_POST_no_csrf_cookie_request() req2 = CsrfMiddleware().process_view(req, post_form_view, (), {}) @@ -252,29 +231,6 @@ class CsrfMiddlewareTest(TestCase): req2 = CsrfMiddleware().process_view(req, post_form_view, (), {}) 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): """ Check that if a CSRF cookie is present and no token, but the csrf_exempt