Fixed #30304 -- Added support for the HttpOnly, SameSite, and Secure flags on language cookies.

This commit is contained in:
Ran Benita 2019-04-01 12:29:10 +03:00 committed by Mariusz Felisiak
parent cef3f2d3c6
commit 19fc6376ce
No known key found for this signature in database
GPG Key ID: 2EF56372BA48CD1B
6 changed files with 68 additions and 1 deletions

View File

@ -154,6 +154,9 @@ LANGUAGE_COOKIE_NAME = 'django_language'
LANGUAGE_COOKIE_AGE = None LANGUAGE_COOKIE_AGE = None
LANGUAGE_COOKIE_DOMAIN = None LANGUAGE_COOKIE_DOMAIN = None
LANGUAGE_COOKIE_PATH = '/' LANGUAGE_COOKIE_PATH = '/'
LANGUAGE_COOKIE_SECURE = False
LANGUAGE_COOKIE_HTTPONLY = False
LANGUAGE_COOKIE_SAMESITE = None
# If you set this to True, Django will format dates, numbers and calendars # If you set this to True, Django will format dates, numbers and calendars

View File

@ -55,6 +55,9 @@ def set_language(request):
max_age=settings.LANGUAGE_COOKIE_AGE, max_age=settings.LANGUAGE_COOKIE_AGE,
path=settings.LANGUAGE_COOKIE_PATH, path=settings.LANGUAGE_COOKIE_PATH,
domain=settings.LANGUAGE_COOKIE_DOMAIN, domain=settings.LANGUAGE_COOKIE_DOMAIN,
secure=settings.LANGUAGE_COOKIE_SECURE,
httponly=settings.LANGUAGE_COOKIE_HTTPONLY,
samesite=settings.LANGUAGE_COOKIE_SAMESITE,
) )
return response return response

View File

@ -1766,6 +1766,21 @@ permanently (via the :setting:`LANGUAGE_COOKIE_NAME` setting) and to add
a middleware that copies the value from the old cookie to a new one and then a middleware that copies the value from the old cookie to a new one and then
deletes the old one. deletes the old one.
.. setting:: LANGUAGE_COOKIE_HTTPONLY
``LANGUAGE_COOKIE_HTTPONLY``
----------------------------
.. versionadded:: 3.0
Default: ``False``
Whether to use ``HttpOnly`` flag on the language cookie. If this is set to
``True``, client-side JavaScript will not to be able to access the language
cookie.
See :setting:`SESSION_COOKIE_HTTPONLY` for details on ``HttpOnly``.
.. setting:: LANGUAGE_COOKIE_NAME .. setting:: LANGUAGE_COOKIE_NAME
``LANGUAGE_COOKIE_NAME`` ``LANGUAGE_COOKIE_NAME``
@ -1800,6 +1815,33 @@ permanently (via the :setting:`LANGUAGE_COOKIE_NAME` setting), and to add
a middleware that copies the value from the old cookie to a new one and then a middleware that copies the value from the old cookie to a new one and then
deletes the one. deletes the one.
.. setting:: LANGUAGE_COOKIE_SAMESITE
``LANGUAGE_COOKIE_SAMESITE``
----------------------------
.. versionadded:: 3.0
Default: ``None``
The value of the `SameSite`_ flag on the language cookie. This flag prevents the
cookie from being sent in cross-site requests.
See :setting:`SESSION_COOKIE_SAMESITE` for details about ``SameSite``.
.. setting:: LANGUAGE_COOKIE_SECURE
``LANGUAGE_COOKIE_SECURE``
--------------------------
.. versionadded:: 3.0
Default: ``False``
Whether to use a secure cookie for the language cookie. If this is set to
``True``, the cookie will be marked as "secure", which means browsers may
ensure that the cookie is only sent under an HTTPS connection.
.. setting:: LANGUAGES .. setting:: LANGUAGES
``LANGUAGES`` ``LANGUAGES``
@ -3402,8 +3444,11 @@ Globalization (``i18n``/``l10n``)
* :setting:`LANGUAGE_CODE` * :setting:`LANGUAGE_CODE`
* :setting:`LANGUAGE_COOKIE_AGE` * :setting:`LANGUAGE_COOKIE_AGE`
* :setting:`LANGUAGE_COOKIE_DOMAIN` * :setting:`LANGUAGE_COOKIE_DOMAIN`
* :setting:`LANGUAGE_COOKIE_HTTPONLY`
* :setting:`LANGUAGE_COOKIE_NAME` * :setting:`LANGUAGE_COOKIE_NAME`
* :setting:`LANGUAGE_COOKIE_PATH` * :setting:`LANGUAGE_COOKIE_PATH`
* :setting:`LANGUAGE_COOKIE_SAMESITE`
* :setting:`LANGUAGE_COOKIE_SECURE`
* :setting:`LANGUAGES` * :setting:`LANGUAGES`
* :setting:`LANGUAGES_BIDI` * :setting:`LANGUAGES_BIDI`
* :setting:`LOCALE_PATHS` * :setting:`LOCALE_PATHS`

View File

@ -153,7 +153,11 @@ Generic Views
Internationalization Internationalization
~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
* ... * Added the :setting:`LANGUAGE_COOKIE_HTTPONLY`,
:setting:`LANGUAGE_COOKIE_SAMESITE`, and :setting:`LANGUAGE_COOKIE_SECURE`
settings to set the ``HttpOnly``, ``SameSite``, and ``Secure`` flags on
language cookies. The default values of these settings preserve the previous
behavior.
Management Commands Management Commands
~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~

View File

@ -1896,7 +1896,10 @@ A number of settings can be used to adjust language cookie options:
* :setting:`LANGUAGE_COOKIE_NAME` * :setting:`LANGUAGE_COOKIE_NAME`
* :setting:`LANGUAGE_COOKIE_AGE` * :setting:`LANGUAGE_COOKIE_AGE`
* :setting:`LANGUAGE_COOKIE_DOMAIN` * :setting:`LANGUAGE_COOKIE_DOMAIN`
* :setting:`LANGUAGE_COOKIE_HTTPONLY`
* :setting:`LANGUAGE_COOKIE_PATH` * :setting:`LANGUAGE_COOKIE_PATH`
* :setting:`LANGUAGE_COOKIE_SAMESITE`
* :setting:`LANGUAGE_COOKIE_SECURE`
Implementation notes Implementation notes
==================== ====================

View File

@ -45,6 +45,9 @@ class SetLanguageTests(TestCase):
self.assertEqual(language_cookie['domain'], '') self.assertEqual(language_cookie['domain'], '')
self.assertEqual(language_cookie['path'], '/') self.assertEqual(language_cookie['path'], '/')
self.assertEqual(language_cookie['max-age'], '') self.assertEqual(language_cookie['max-age'], '')
self.assertEqual(language_cookie['httponly'], '')
self.assertEqual(language_cookie['samesite'], '')
self.assertEqual(language_cookie['secure'], '')
def test_setlang_unsafe_next(self): def test_setlang_unsafe_next(self):
""" """
@ -175,6 +178,9 @@ class SetLanguageTests(TestCase):
'LANGUAGE_COOKIE_AGE': 3600 * 7 * 2, 'LANGUAGE_COOKIE_AGE': 3600 * 7 * 2,
'LANGUAGE_COOKIE_DOMAIN': '.example.com', 'LANGUAGE_COOKIE_DOMAIN': '.example.com',
'LANGUAGE_COOKIE_PATH': '/test/', 'LANGUAGE_COOKIE_PATH': '/test/',
'LANGUAGE_COOKIE_HTTPONLY': True,
'LANGUAGE_COOKIE_SAMESITE': 'Strict',
'LANGUAGE_COOKIE_SECURE': True,
} }
with self.settings(**test_settings): with self.settings(**test_settings):
post_data = {'language': 'pl', 'next': '/views/'} post_data = {'language': 'pl', 'next': '/views/'}
@ -184,6 +190,9 @@ class SetLanguageTests(TestCase):
self.assertEqual(language_cookie['domain'], '.example.com') self.assertEqual(language_cookie['domain'], '.example.com')
self.assertEqual(language_cookie['path'], '/test/') self.assertEqual(language_cookie['path'], '/test/')
self.assertEqual(language_cookie['max-age'], 3600 * 7 * 2) self.assertEqual(language_cookie['max-age'], 3600 * 7 * 2)
self.assertEqual(language_cookie['httponly'], True)
self.assertEqual(language_cookie['samesite'], 'Strict')
self.assertEqual(language_cookie['secure'], True)
def test_setlang_decodes_http_referer_url(self): def test_setlang_decodes_http_referer_url(self):
""" """