Loading django/middleware/csrf.py +23 −52 Original line number Diff line number Diff line Loading @@ -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." Loading Loading @@ -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 Loading Loading @@ -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), 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_COOKIE) else: csrf_token = request.META["CSRF_COOKIE"] return self._reject(request, REASON_NO_CSRF_COOKIE) # check incoming token request_csrf_token = request.POST.get('csrfmiddlewaretoken', '') Loading @@ -202,16 +183,6 @@ 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, Loading tests/regressiontests/csrf_tests/tests.py +3 −47 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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, Loading Loading @@ -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)) Loading Loading @@ -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, (), {}) Loading @@ -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 Loading Loading
django/middleware/csrf.py +23 −52 Original line number Diff line number Diff line Loading @@ -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." Loading Loading @@ -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 Loading Loading @@ -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), 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_COOKIE) else: csrf_token = request.META["CSRF_COOKIE"] return self._reject(request, REASON_NO_CSRF_COOKIE) # check incoming token request_csrf_token = request.POST.get('csrfmiddlewaretoken', '') Loading @@ -202,16 +183,6 @@ 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, Loading
tests/regressiontests/csrf_tests/tests.py +3 −47 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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, Loading Loading @@ -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)) Loading Loading @@ -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, (), {}) Loading @@ -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 Loading