Loading django/contrib/csrf/middleware.py +21 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,10 @@ against request forgeries from other sites. import re import itertools try: from functools import wraps except ImportError: from django.utils.functional import wraps # Python 2.3, 2.4 fallback. from django.conf import settings from django.http import HttpResponseForbidden Loading @@ -30,6 +34,12 @@ class CsrfViewMiddleware(object): """ def process_view(self, request, callback, callback_args, callback_kwargs): if request.method == 'POST': if getattr(callback, 'csrf_exempt', False): return None if request.is_ajax(): return None try: session_id = request.COOKIES[settings.SESSION_COOKIE_NAME] except KeyError: Loading Loading @@ -107,3 +117,14 @@ class CsrfMiddleware(CsrfViewMiddleware, CsrfResponseMiddleware): and CsrfResponseMiddleware which can be used independently. """ pass def csrf_exempt(view_func): """ Marks a view function as being exempt from the CSRF checks """ def wrapped_view(*args, **kwargs): return view_func(*args, **kwargs) # We could just do view.csrf_exempt = True, but decorators are # nicer if they don't have side-effects. wrapped_view.csrf_exempt = True return wraps(view_func)(wrapped_view) django/contrib/csrf/tests.py +30 −7 Original line number Diff line number Diff line Loading @@ -2,10 +2,19 @@ from django.test import TestCase from django.http import HttpRequest, HttpResponse, HttpResponseForbidden from django.contrib.csrf.middleware import CsrfMiddleware, _make_token from django.contrib.csrf.middleware import CsrfMiddleware, _make_token, csrf_exempt from django.conf import settings def post_form_response(): resp = HttpResponse(content=""" <html><body><form method="POST"><input type="text" /></form></body></html> """, mimetype="text/html") return resp def test_view(request): return post_form_response() class CsrfMiddlewareTest(TestCase): _session_id = "1" Loading Loading @@ -34,10 +43,7 @@ class CsrfMiddlewareTest(TestCase): return req def _get_post_form_response(self): resp = HttpResponse(content=""" <html><body><form method="POST"><input type="text" /></form></body></html> """, mimetype="text/html") return resp return post_form_response() def _get_new_session_response(self): resp = self._get_post_form_response() Loading @@ -48,8 +54,7 @@ class CsrfMiddlewareTest(TestCase): self.assertContains(response, "name='csrfmiddlewaretoken' value='%s'" % _make_token(self._session_id)) def get_view(self): def dummyview(request): return self._get_post_form_response() return test_view # Check the post processing def test_process_response_no_session(self): Loading Loading @@ -109,3 +114,21 @@ class CsrfMiddlewareTest(TestCase): req = self._get_POST_session_request_with_token() req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {}) self.assertEquals(None, req2) def test_process_request_session_no_token_exempt_view(self): """ Check that if a session 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_session_request() req2 = CsrfMiddleware().process_view(req, csrf_exempt(self.get_view()), (), {}) self.assertEquals(None, req2) def test_ajax_exemption(self): """ Check the AJAX requests are automatically exempted. """ req = self._get_POST_session_request() req.META['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest' req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {}) self.assertEquals(None, req2) docs/ref/contrib/csrf.txt +25 −2 Original line number Diff line number Diff line Loading @@ -26,7 +26,18 @@ Add the middleware ``'django.contrib.csrf.middleware.CsrfMiddleware'`` to your list of middleware classes, :setting:`MIDDLEWARE_CLASSES`. It needs to process the response after the SessionMiddleware, so must come before it in the list. It also must process the response before things like compression happen to the response, so it must come after GZipMiddleware in the list. happen to the response, so it must come after GZipMiddleware in the list. Exceptions ---------- To manually exclude a view function from being handled by the CsrfMiddleware, you can use the ``csrf_exempt`` decorator (found in the ``django.contrib.csrf.middleware`` module). AJAX requests sent with "X-Requested-With: XMLHttpRequest" are automatically exempt (see below). How it works ============ Loading Loading @@ -59,6 +70,18 @@ The Content-Type is checked before modifying the response, and only pages that are served as 'text/html' or 'application/xml+xhtml' are modified. AJAX requests sent with "X-Requested-With: XMLHttpRequest", as done by many AJAX toolkits, are detected and automatically excepted from this mechanism. This is because in the context of a browser, this header can only be added by using XMLHttpRequest, and browsers already implement a same-domain policy for XMLHttpRequest. This is not secure if you do not trust content within the same domain or sub-domains. The above two functions of ``CsrfMiddleware`` are split between two classes: ``CsrfResponseMiddleware`` and ``CsrfViewMiddleware`` respectively. This allows the individual components to be used and/or replaced instead of using ``CsrfMiddleware``. .. _9.1.1 Safe Methods, HTTP 1.1, RFC 2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html Limitations Loading Loading
django/contrib/csrf/middleware.py +21 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,10 @@ against request forgeries from other sites. import re import itertools try: from functools import wraps except ImportError: from django.utils.functional import wraps # Python 2.3, 2.4 fallback. from django.conf import settings from django.http import HttpResponseForbidden Loading @@ -30,6 +34,12 @@ class CsrfViewMiddleware(object): """ def process_view(self, request, callback, callback_args, callback_kwargs): if request.method == 'POST': if getattr(callback, 'csrf_exempt', False): return None if request.is_ajax(): return None try: session_id = request.COOKIES[settings.SESSION_COOKIE_NAME] except KeyError: Loading Loading @@ -107,3 +117,14 @@ class CsrfMiddleware(CsrfViewMiddleware, CsrfResponseMiddleware): and CsrfResponseMiddleware which can be used independently. """ pass def csrf_exempt(view_func): """ Marks a view function as being exempt from the CSRF checks """ def wrapped_view(*args, **kwargs): return view_func(*args, **kwargs) # We could just do view.csrf_exempt = True, but decorators are # nicer if they don't have side-effects. wrapped_view.csrf_exempt = True return wraps(view_func)(wrapped_view)
django/contrib/csrf/tests.py +30 −7 Original line number Diff line number Diff line Loading @@ -2,10 +2,19 @@ from django.test import TestCase from django.http import HttpRequest, HttpResponse, HttpResponseForbidden from django.contrib.csrf.middleware import CsrfMiddleware, _make_token from django.contrib.csrf.middleware import CsrfMiddleware, _make_token, csrf_exempt from django.conf import settings def post_form_response(): resp = HttpResponse(content=""" <html><body><form method="POST"><input type="text" /></form></body></html> """, mimetype="text/html") return resp def test_view(request): return post_form_response() class CsrfMiddlewareTest(TestCase): _session_id = "1" Loading Loading @@ -34,10 +43,7 @@ class CsrfMiddlewareTest(TestCase): return req def _get_post_form_response(self): resp = HttpResponse(content=""" <html><body><form method="POST"><input type="text" /></form></body></html> """, mimetype="text/html") return resp return post_form_response() def _get_new_session_response(self): resp = self._get_post_form_response() Loading @@ -48,8 +54,7 @@ class CsrfMiddlewareTest(TestCase): self.assertContains(response, "name='csrfmiddlewaretoken' value='%s'" % _make_token(self._session_id)) def get_view(self): def dummyview(request): return self._get_post_form_response() return test_view # Check the post processing def test_process_response_no_session(self): Loading Loading @@ -109,3 +114,21 @@ class CsrfMiddlewareTest(TestCase): req = self._get_POST_session_request_with_token() req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {}) self.assertEquals(None, req2) def test_process_request_session_no_token_exempt_view(self): """ Check that if a session 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_session_request() req2 = CsrfMiddleware().process_view(req, csrf_exempt(self.get_view()), (), {}) self.assertEquals(None, req2) def test_ajax_exemption(self): """ Check the AJAX requests are automatically exempted. """ req = self._get_POST_session_request() req.META['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest' req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {}) self.assertEquals(None, req2)
docs/ref/contrib/csrf.txt +25 −2 Original line number Diff line number Diff line Loading @@ -26,7 +26,18 @@ Add the middleware ``'django.contrib.csrf.middleware.CsrfMiddleware'`` to your list of middleware classes, :setting:`MIDDLEWARE_CLASSES`. It needs to process the response after the SessionMiddleware, so must come before it in the list. It also must process the response before things like compression happen to the response, so it must come after GZipMiddleware in the list. happen to the response, so it must come after GZipMiddleware in the list. Exceptions ---------- To manually exclude a view function from being handled by the CsrfMiddleware, you can use the ``csrf_exempt`` decorator (found in the ``django.contrib.csrf.middleware`` module). AJAX requests sent with "X-Requested-With: XMLHttpRequest" are automatically exempt (see below). How it works ============ Loading Loading @@ -59,6 +70,18 @@ The Content-Type is checked before modifying the response, and only pages that are served as 'text/html' or 'application/xml+xhtml' are modified. AJAX requests sent with "X-Requested-With: XMLHttpRequest", as done by many AJAX toolkits, are detected and automatically excepted from this mechanism. This is because in the context of a browser, this header can only be added by using XMLHttpRequest, and browsers already implement a same-domain policy for XMLHttpRequest. This is not secure if you do not trust content within the same domain or sub-domains. The above two functions of ``CsrfMiddleware`` are split between two classes: ``CsrfResponseMiddleware`` and ``CsrfViewMiddleware`` respectively. This allows the individual components to be used and/or replaced instead of using ``CsrfMiddleware``. .. _9.1.1 Safe Methods, HTTP 1.1, RFC 2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html Limitations Loading