def check_csrf(request: HttpRequest, callback: Callable) -> Optional[HttpResponseForbidden]: mware = CsrfViewMiddleware( lambda x: HttpResponseForbidden()) # pragma: no cover request.csrf_processing_done = False # type: ignore mware.process_request(request) return mware.process_view(request, callback, (), {})
def test_no_session_on_request(self): msg = ( 'CSRF_USE_SESSIONS is enabled, but request.session is not set. ' 'SessionMiddleware must appear before CsrfViewMiddleware in MIDDLEWARE.' ) with self.assertRaisesMessage(ImproperlyConfigured, msg): mw = CsrfViewMiddleware(lambda req: HttpResponse()) mw.process_request(HttpRequest())
def test_process_request_csrf_cookie_and_token(self): """ If both a cookie and a token is present, the middleware lets it through. """ req = self._get_POST_request_with_token() mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) resp = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(resp)
def _test_https_good_referer_matches_cookie_domain(self): req = self._get_POST_request_with_token() req._is_secure_override = True req.META['HTTP_REFERER'] = 'https://foo.example.com/' req.META['SERVER_PORT'] = '443' mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) response = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(response)
def test_csrf_token_in_header(self): """ The token may be passed in a header instead of in the form. """ req = self._get_POST_csrf_cookie_request() req.META['HTTP_X_CSRFTOKEN'] = self._csrf_id mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) resp = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(resp)
def test_token_node_with_csrf_cookie(self): """ CsrfTokenNode works when a CSRF cookie is set. """ req = self._get_GET_csrf_cookie_request() mw = CsrfViewMiddleware(token_view) mw.process_request(req) mw.process_view(req, token_view, (), {}) resp = token_view(req) self._check_token_present(resp)
def test_process_request_csrf_cookie_no_token_exempt_view(self): """ If a CSRF cookie is present and no token, but the csrf_exempt decorator has been applied to the view, the middleware lets it through """ req = self._get_POST_csrf_cookie_request() mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) resp = mw.process_view(req, csrf_exempt(post_form_view), (), {}) self.assertIsNone(resp)
def test_get_token_for_exempt_view(self): """ get_token still works for a view decorated with 'csrf_exempt'. """ req = self._get_GET_csrf_cookie_request() mw = CsrfViewMiddleware(token_view) mw.process_request(req) mw.process_view(req, csrf_exempt(token_view), (), {}) resp = token_view(req) self._check_token_present(resp)
def test_csrf_token_in_header_with_customized_name(self): """ settings.CSRF_HEADER_NAME can be used to customize the CSRF header name """ req = self._get_POST_csrf_cookie_request() req.META['HTTP_X_CSRFTOKEN_CUSTOMIZED'] = self._csrf_id mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) resp = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(resp)
def test_post_data_read_failure(self): """ OSErrors during POST data reading are caught and treated as if the POST data wasn't there (#20128). """ class CsrfPostRequest(HttpRequest): """ HttpRequest that can raise an OSError when accessing POST data """ def __init__(self, token, raise_error): super().__init__() self.method = 'POST' self.raise_error = False self.COOKIES[settings.CSRF_COOKIE_NAME] = token # Handle both cases here to prevent duplicate code in the # session tests. self.session = {} self.session[CSRF_SESSION_KEY] = token self.POST['csrfmiddlewaretoken'] = token self.raise_error = raise_error def _load_post_and_files(self): raise OSError('error reading input data') def _get_post(self): if self.raise_error: self._load_post_and_files() return self._post def _set_post(self, post): self._post = post POST = property(_get_post, _set_post) token = ('ABC' + self._csrf_id)[:CSRF_TOKEN_LENGTH] req = CsrfPostRequest(token, raise_error=False) mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) resp = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(resp) req = CsrfPostRequest(token, raise_error=True) mw.process_request(req) with self.assertLogs('django.security.csrf', 'WARNING') as cm: resp = mw.process_view(req, post_form_view, (), {}) self.assertEqual(resp.status_code, 403) self.assertEqual( cm.records[0].getMessage(), 'Forbidden (%s): ' % REASON_CSRF_TOKEN_MISSING, )
def test_process_request_csrf_cookie_no_token(self): """ If a CSRF cookie is present but no token, the middleware rejects the incoming request. """ req = self._get_POST_csrf_cookie_request() mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) with self.assertLogs('django.security.csrf', 'WARNING') as cm: resp = mw.process_view(req, post_form_view, (), {}) self.assertEqual(403, resp.status_code) self.assertEqual(cm.records[0].getMessage(), 'Forbidden (%s): ' % REASON_BAD_TOKEN)
def test_process_request_no_csrf_cookie(self): """ 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() mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) with self.assertLogs('django.security.csrf', 'WARNING') as cm: resp = mw.process_view(req, post_form_view, (), {}) self.assertEqual(403, resp.status_code) self.assertEqual(cm.records[0].getMessage(), 'Forbidden (%s): ' % REASON_NO_CSRF_COOKIE)
def test_https_good_referer(self): """ A POST HTTPS request with a good referer is accepted. """ req = self._get_POST_request_with_token() req._is_secure_override = True req.META['HTTP_HOST'] = 'www.example.com' req.META['HTTP_REFERER'] = 'https://www.example.com/somepage' mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) resp = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(resp)
def _check_bad_or_missing_token(self, token, expected): """Passing None for token includes no token.""" if token is None: req = self._get_POST_csrf_cookie_request() else: req = self._get_POST_request_with_token(token=token) mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) with self.assertLogs('django.security.csrf', 'WARNING') as cm: resp = mw.process_view(req, post_form_view, (), {}) self.assertEqual(403, resp.status_code) self.assertEqual(cm.records[0].getMessage(), 'Forbidden (%s): ' % expected)
def test_https_good_referer_malformed_host(self): """ A POST HTTPS request is accepted if it receives a good referer with a bad host. """ req = self._get_POST_request_with_token() req._is_secure_override = True req.META['HTTP_HOST'] = '@malformed' req.META['HTTP_REFERER'] = 'https://dashboard.example.com/somepage' mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) resp = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(resp)
def enforce_csrf(self, request): """ Enforce CSRF validation """ check = CsrfViewMiddleware() # populates request.META['CSRF_COOKIE'], which is used in process_view() check.process_request(request) breakpoint() reason = check.process_view(request, None, (), {}) print(reason) if reason: # CSRF failed, bail with explicit error message raise exceptions.PermissionDenied('CSRF Failed: %s' % reason)
def test_https_csrf_wildcard_trusted_origin_allowed(self): """ A POST HTTPS request with a referer that matches a CSRF_TRUSTED_ORIGINS wildcard is accepted. """ req = self._get_POST_request_with_token() req._is_secure_override = True req.META['HTTP_HOST'] = 'www.example.com' req.META['HTTP_REFERER'] = 'https://dashboard.example.com' mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) response = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(response)
def _test_https_good_referer_behind_proxy(self): req = self._get_POST_request_with_token() req._is_secure_override = True req.META.update({ 'HTTP_HOST': '10.0.0.2', 'HTTP_REFERER': 'https://www.example.com/somepage', 'SERVER_PORT': '8080', 'HTTP_X_FORWARDED_HOST': 'www.example.com', 'HTTP_X_FORWARDED_PORT': '443', }) mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) resp = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(resp)
def test_https_good_referer_2(self): """ A POST HTTPS request with a good referer is accepted where the referer contains no trailing slash. """ # See ticket #15617 req = self._get_POST_request_with_token() req._is_secure_override = True req.META['HTTP_HOST'] = 'www.example.com' req.META['HTTP_REFERER'] = 'https://www.example.com' mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) resp = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(resp)
def test_bare_secret_accepted_and_replaced(self): """ The csrf token is reset from a bare secret. """ req = self._get_POST_bare_secret_csrf_cookie_request_with_token() mw = CsrfViewMiddleware(token_view) mw.process_request(req) resp = mw.process_view(req, token_view, (), {}) self.assertIsNone(resp) resp = mw(req) self.assertIn(settings.CSRF_COOKIE_NAME, resp.cookies, "Cookie was not reset from bare secret") csrf_cookie = resp.cookies[settings.CSRF_COOKIE_NAME] self.assertEqual(len(csrf_cookie.value), CSRF_TOKEN_LENGTH) self._check_token_present(resp, csrf_id=csrf_cookie.value)
def test_cookie_not_reset_on_accepted_request(self): """ The csrf token used in posts is changed on every request (although stays equivalent). The csrf cookie should not change on accepted requests. If it appears in the response, it should keep its value. """ req = self._get_POST_request_with_token() mw = CsrfViewMiddleware(token_view) mw.process_request(req) mw.process_view(req, token_view, (), {}) resp = mw(req) csrf_cookie = resp.cookies.get(settings.CSRF_COOKIE_NAME, None) if csrf_cookie: self.assertEqual(csrf_cookie.value, self._csrf_id_cookie, "CSRF cookie was changed on an accepted request")
def test_put_and_delete_allowed(self): """ HTTP PUT and DELETE can get through with X-CSRFToken and a cookie. """ req = self._get_GET_csrf_cookie_request() req.method = 'PUT' req.META['HTTP_X_CSRFTOKEN'] = self._csrf_id mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) resp = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(resp) req = self._get_GET_csrf_cookie_request() req.method = 'DELETE' req.META['HTTP_X_CSRFTOKEN'] = self._csrf_id mw.process_request(req) resp = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(resp)
def test_process_response_get_token_not_used(self): """ If get_token() is not called, the view middleware does not add a cookie. """ # This is important to make pages cacheable. Pages which do call # get_token(), assuming they use the token, are not cacheable because # the token is specific to the user req = self._get_GET_no_csrf_cookie_request() # non_token_view_using_request_processor does not call get_token(), but # does use the csrf request processor. By using this, we are testing # that the view processor is properly lazy and doesn't call get_token() # until needed. mw = CsrfViewMiddleware(non_token_view_using_request_processor) mw.process_request(req) mw.process_view(req, non_token_view_using_request_processor, (), {}) resp = mw(req) csrf_cookie = resp.cookies.get(settings.CSRF_COOKIE_NAME, False) self.assertIs(csrf_cookie, False)
def check_csrf(request: HttpRequest, callback: Callable): mware = CsrfViewMiddleware(lambda: None) request.csrf_processing_done = False mware.process_request(request) return mware.process_view(request, callback, [], {})