Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fixed #22185 -- Added settings.CSRF_COOKIE_AGE

Thanks Paul McMillan for the review.
  • Loading branch information...
commit 9b729ddd8f2040722971ccfb3b12f7d8162633d1 1 parent 06efeae
@rogerhu rogerhu authored timgraham committed
View
1  django/conf/global_settings.py
@@ -558,6 +558,7 @@
# Settings for CSRF cookie.
CSRF_COOKIE_NAME = 'csrftoken'
+CSRF_COOKIE_AGE = 60 * 60 * 24 * 7 * 52
CSRF_COOKIE_DOMAIN = None
CSRF_COOKIE_PATH = '/'
CSRF_COOKIE_SECURE = False
View
2  django/middleware/csrf.py
@@ -196,7 +196,7 @@ def process_response(self, request, response):
# the expiry timer.
response.set_cookie(settings.CSRF_COOKIE_NAME,
request.META["CSRF_COOKIE"],
- max_age=60 * 60 * 24 * 7 * 52,
+ max_age=settings.CSRF_COOKIE_AGE,
domain=settings.CSRF_COOKIE_DOMAIN,
path=settings.CSRF_COOKIE_PATH,
secure=settings.CSRF_COOKIE_SECURE,
View
1  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_AGE`
* :setting:`CSRF_COOKIE_DOMAIN`
* :setting:`CSRF_COOKIE_HTTPONLY`
* :setting:`CSRF_COOKIE_NAME`
View
22 docs/ref/settings.txt
@@ -324,6 +324,28 @@ See :doc:`/topics/cache`.
.. _settings-csrf:
+.. setting:: CSRF_COOKIE_AGE
+
+CSRF_COOKIE_AGE
+---------------
+
+.. versionadded:: 1.7
+
+Default: ``31449600`` (1 year, in seconds)
+
+The age of CSRF cookies, in seconds.
+
+The reason for setting a long-lived expiration time is to avoid problems in
+the case of a user closing a browser or bookmarking a page and then loading
+that page from a browser cache. Without persistent cookies, the form submission
+would fail in this case.
+
+Some browsers (specifically Internet Explorer) can disallow the use of
+persistent cookies or can have the indexes to the cookie jar corrupted on disk,
+thereby causing CSRF protection checks to fail (and sometimes intermittently).
+Change this setting to ``None`` to use session-based CSRF cookies, which
+keep the cookies in-memory instead of on persistent storage.
+
.. setting:: CSRF_COOKIE_DOMAIN
CSRF_COOKIE_DOMAIN
View
6 docs/releases/1.7.txt
@@ -446,6 +446,12 @@ Cache
"non-expiring" by default. Previously, it was only possible to pass
``timeout=None` to the cache backend's ``set()`` method.
+Cross Site Request Forgery
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* The :setting:`CSRF_COOKIE_AGE` setting facilitates the use of session-based
+ CSRF cookies.
+
Email
^^^^^
View
44 tests/csrf_tests/tests.py
@@ -384,3 +384,47 @@ def emit(self, record):
finally:
logger.removeHandler(test_handler)
logger.setLevel(old_log_level)
+
+ def test_csrf_cookie_age(self):
+ """
+ Test to verify CSRF cookie age can be set using
+ settings.CSRF_COOKIE_AGE.
+ """
+ req = self._get_GET_no_csrf_cookie_request()
+
+ MAX_AGE = 123
+ with self.settings(CSRF_COOKIE_NAME='csrfcookie',
+ CSRF_COOKIE_DOMAIN='.example.com',
+ CSRF_COOKIE_AGE=MAX_AGE,
+ CSRF_COOKIE_PATH='/test/',
+ CSRF_COOKIE_SECURE=True,
+ CSRF_COOKIE_HTTPONLY=True):
+ # token_view calls get_token() indirectly
+ CsrfViewMiddleware().process_view(req, token_view, (), {})
+ resp = token_view(req)
+
+ resp2 = CsrfViewMiddleware().process_response(req, resp)
+ max_age = resp2.cookies.get('csrfcookie').get('max-age')
+ self.assertEqual(max_age, MAX_AGE)
+
+ def test_csrf_cookie_age_none(self):
+ """
+ Test to verify CSRF cookie age does not have max age set and therefore
+ uses session-based cookies.
+ """
+ req = self._get_GET_no_csrf_cookie_request()
+
+ MAX_AGE = None
+ with self.settings(CSRF_COOKIE_NAME='csrfcookie',
+ CSRF_COOKIE_DOMAIN='.example.com',
+ CSRF_COOKIE_AGE=MAX_AGE,
+ CSRF_COOKIE_PATH='/test/',
+ CSRF_COOKIE_SECURE=True,
+ CSRF_COOKIE_HTTPONLY=True):
+ # token_view calls get_token() indirectly
+ CsrfViewMiddleware().process_view(req, token_view, (), {})
+ resp = token_view(req)
+
+ resp2 = CsrfViewMiddleware().process_response(req, resp)
+ max_age = resp2.cookies.get('csrfcookie').get('max-age')
+ self.assertEqual(max_age, '')
Please sign in to comment.
Something went wrong with that request. Please try again.