Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Emulate browser's cookie domains behaviour

For compatibility with cookie domain setting, origin check emulates
the behaviour of browser cookie-domain validator.

Signed-off-by: Rohan Jain <crodjer@gmail.com>
  • Loading branch information...
commit 46a2f7b1768712e7c723e047beb71bb9b59610bb 1 parent 13ba162
@crodjer authored
View
21 django/middleware/csrf.py
@@ -116,12 +116,25 @@ def process_view(self, request, callback, callback_args, callback_kwargs):
host = request.META.get('HTTP_HOST', '')
origin = request.META.get('HTTP_ORIGIN')
- cookie_domain = getattr(settings, 'CSRF_COOKIE_DOMAIN') or host
+ good_origin = settings.CSRF_COOKIE_DOMAIN or host
+ # If origin header exists, use it to check for csrf attacks.
+ # Origin header is being compared to None here as we need to reject
+ # requests with origin header as '' too, which otherwise is treated
+ # as null.
if origin is not None:
- # TODO: Fix this check to be like browser cookie check
- if not origin.endswith(cookie_domain):
- reason = REASON_BAD_ORIGIN % (origin, cookie_domain)
+
+ # If the good origin starts with a dot (.), it means the cookie
+ # is supposed to work across all the subdomains, i.e. an
+ # endswith test and a count of dots should be fine here.
+ # In case case the actual and the good origin are the same, then
+ # too it passes.
+ if not ((good_origin.startswith('.')
+ and good_origin.count('.') is origin.count('.')
+ and origin.endswith(good_origin))
+ or origin[origin.find('://')+3:] == good_origin):
+
+ reason = REASON_BAD_ORIGIN % (origin, good_origin)
logger.warning('Forbidden (%s): %s',
reason, request.path,
extra={
View
59 tests/regressiontests/csrf_tests/tests.py
@@ -7,6 +7,7 @@
from django.template import RequestContext, Template
from django.test import TestCase
from django.views.decorators.csrf import csrf_exempt, requires_csrf_token, ensure_csrf_cookie
+from django.test.utils import override_settings
# Response/views used for CsrfResponseMiddleware and CsrfViewMiddleware tests
@@ -334,9 +335,42 @@ def view(request):
self.assertTrue(resp2.cookies.get(settings.CSRF_COOKIE_NAME, False))
self.assertTrue('Cookie' in resp2.get('Vary',''))
+ @override_settings(CSRF_COOKIE_DOMAIN='.example.com')
def test_good_origin_header(self):
"""
- Test if a good origin header is accepted.
+ Test if a good origin header is accepted for across subdomain settings.
+ """
+ req = self._get_POST_request_with_token()
+ req.META['HTTP_HOST'] = 'www.example.com'
+ req.META['HTTP_ORIGIN'] = 'http://www.example.com'
+ req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
+ self.assertEqual(None, req2)
+
+ @override_settings(CSRF_COOKIE_DOMAIN='www.example.com')
+ def test_good_origin_header_2(self):
+ """
+ Test if a good origin header is accepted for a single subdomain.
+ """
+ req = self._get_POST_request_with_token()
+ req.META['HTTP_HOST'] = 'www.example.com'
+ req.META['HTTP_ORIGIN'] = 'http://www.example.com'
+ req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
+ self.assertEqual(None, req2)
+
+ @override_settings(CSRF_COOKIE_DOMAIN='example.com')
+ def test_good_origin_header_3(self):
+ """
+ Test if a good origin header is accepted for a no subdomain.
+ """
+ req = self._get_POST_request_with_token()
+ req.META['HTTP_HOST'] = 'example.com'
+ req.META['HTTP_ORIGIN'] = 'http://example.com'
+ req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
+ self.assertEqual(None, req2)
+
+ def test_good_origin_header_4(self):
+ """
+ Test if a good origin header is accepted for no cookie setting.
"""
req = self._get_POST_request_with_token()
req.META['HTTP_HOST'] = 'www.example.com'
@@ -346,7 +380,28 @@ def test_good_origin_header(self):
def test_bad_origin_header(self):
"""
- Test if a bad origin header is rejected.
+ Test if a bad origin header is rejected for different domain.
+ """
+ req = self._get_POST_request_with_token()
+ req.META['HTTP_HOST'] = 'www.example.com'
+ req.META['HTTP_ORIGIN'] = 'http://www.evil.com'
+ req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
+ self.assertEqual(403, req2.status_code)
+
+ @override_settings(CSRF_COOKIE_DOMAIN='example.com')
+ def test_bad_origin_header_2(self):
+ """
+ Test if a bad origin header is rejected for subdomains.
+ """
+ req = self._get_POST_request_with_token()
+ req.META['HTTP_HOST'] = 'www.example.com'
+ req.META['HTTP_ORIGIN'] = 'http://www.example.com'
+ req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
+ self.assertEqual(403, req2.status_code)
+
+ def test_bad_origin_header_3(self):
+ """
+ Test if a bad origin header is rejected with no cookie setting.
"""
req = self._get_POST_request_with_token()
req.META['HTTP_HOST'] = 'www.example.com'

0 comments on commit 46a2f7b

Please sign in to comment.
Something went wrong with that request. Please try again.