From 720888a14699a80a6cd07d32514b9dcd5b1005fb Mon Sep 17 00:00:00 2001 From: Aymeric Augustin Date: Thu, 7 Feb 2013 09:48:08 +0100 Subject: [PATCH] Fixed #15808 -- Added optional HttpOnly flag to the CSRF Cookie. Thanks Samuel Lavitt for the report and Sascha Peilicke for the patch. --- django/conf/global_settings.py | 1 + django/middleware/csrf.py | 3 ++- docs/ref/contrib/csrf.txt | 1 + docs/ref/settings.txt | 13 +++++++++++++ docs/releases/1.6.txt | 3 +++ tests/regressiontests/csrf_tests/tests.py | 4 +++- 6 files changed, 23 insertions(+), 2 deletions(-) diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py index 740c792dcf..6a01493a72 100644 --- a/django/conf/global_settings.py +++ b/django/conf/global_settings.py @@ -529,6 +529,7 @@ CSRF_COOKIE_NAME = 'csrftoken' CSRF_COOKIE_DOMAIN = None CSRF_COOKIE_PATH = '/' CSRF_COOKIE_SECURE = False +CSRF_COOKIE_HTTPONLY = False ############ # MESSAGES # diff --git a/django/middleware/csrf.py b/django/middleware/csrf.py index 339f42a110..423034478b 100644 --- a/django/middleware/csrf.py +++ b/django/middleware/csrf.py @@ -210,7 +210,8 @@ class CsrfViewMiddleware(object): max_age = 60 * 60 * 24 * 7 * 52, domain=settings.CSRF_COOKIE_DOMAIN, path=settings.CSRF_COOKIE_PATH, - secure=settings.CSRF_COOKIE_SECURE + secure=settings.CSRF_COOKIE_SECURE, + httponly=settings.CSRF_COOKIE_HTTPONLY ) # Content varies with the CSRF cookie, so set the Vary header. patch_vary_headers(response, ('Cookie',)) diff --git a/docs/ref/contrib/csrf.txt b/docs/ref/contrib/csrf.txt index 3ad16e2f97..14522d8dbc 100644 --- a/docs/ref/contrib/csrf.txt +++ b/docs/ref/contrib/csrf.txt @@ -491,6 +491,7 @@ Settings A number of settings can be used to control Django's CSRF behavior: * :setting:`CSRF_COOKIE_DOMAIN` +* :setting:`CSRF_COOKIE_HTTPONLY` * :setting:`CSRF_COOKIE_NAME` * :setting:`CSRF_COOKIE_PATH` * :setting:`CSRF_COOKIE_SECURE` diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt index d4c6868ced..9a615b2d99 100644 --- a/docs/ref/settings.txt +++ b/docs/ref/settings.txt @@ -281,6 +281,19 @@ Please note that the presence of this setting does not imply that Django's CSRF protection is safe from cross-subdomain attacks by default - please see the :ref:`CSRF limitations ` section. +.. setting:: CSRF_COOKIE_HTTPONLY + +CSRF_COOKIE_HTTPONLY +-------------------- + +.. versionadded:: 1.6 + +Default: ``False`` + +Whether to use HttpOnly flag on the CSRF cookie. If this is set to ``True``, +client-side JavaScript will not to be able to access the CSRF cookie. See +:setting:`SESSION_COOKIE_HTTPONLY` for details on HttpOnly. + .. setting:: CSRF_COOKIE_NAME CSRF_COOKIE_NAME diff --git a/docs/releases/1.6.txt b/docs/releases/1.6.txt index f86d8b8108..f53fa8ac4c 100644 --- a/docs/releases/1.6.txt +++ b/docs/releases/1.6.txt @@ -36,6 +36,9 @@ Minor features * Authentication backends can raise ``PermissionDenied`` to immediately fail the authentication chain. +* The HttpOnly flag can be set on the CSRF cookie with + :setting:`CSRF_COOKIE_HTTPONLY`. + * The ``assertQuerysetEqual()`` now checks for undefined order and raises ``ValueError`` if undefined order is spotted. The order is seen as undefined if the given ``QuerySet`` isn't ordered and there are more than diff --git a/tests/regressiontests/csrf_tests/tests.py b/tests/regressiontests/csrf_tests/tests.py index c5b66a31d1..3719108962 100644 --- a/tests/regressiontests/csrf_tests/tests.py +++ b/tests/regressiontests/csrf_tests/tests.py @@ -101,7 +101,8 @@ class CsrfViewMiddlewareTest(TestCase): with self.settings(CSRF_COOKIE_NAME='myname', CSRF_COOKIE_DOMAIN='.example.com', CSRF_COOKIE_PATH='/test/', - CSRF_COOKIE_SECURE=True): + CSRF_COOKIE_SECURE=True, + CSRF_COOKIE_HTTPONLY=True): # token_view calls get_token() indirectly CsrfViewMiddleware().process_view(req, token_view, (), {}) resp = token_view(req) @@ -110,6 +111,7 @@ class CsrfViewMiddlewareTest(TestCase): self.assertNotEqual(csrf_cookie, False) self.assertEqual(csrf_cookie['domain'], '.example.com') self.assertEqual(csrf_cookie['secure'], True) + self.assertEqual(csrf_cookie['httponly'], True) self.assertEqual(csrf_cookie['path'], '/test/') self.assertTrue('Cookie' in resp2.get('Vary',''))