Fixed #26947 -- Added an option to enable the HSTS header preload directive.

This commit is contained in:
Ed Morley 2016-07-28 17:48:07 +01:00 committed by Tim Graham
parent c412aaca73
commit 3c2447dd13
7 changed files with 67 additions and 4 deletions

View File

@ -629,6 +629,7 @@ SILENCED_SYSTEM_CHECKS = []
SECURE_BROWSER_XSS_FILTER = False SECURE_BROWSER_XSS_FILTER = False
SECURE_CONTENT_TYPE_NOSNIFF = False SECURE_CONTENT_TYPE_NOSNIFF = False
SECURE_HSTS_INCLUDE_SUBDOMAINS = False SECURE_HSTS_INCLUDE_SUBDOMAINS = False
SECURE_HSTS_PRELOAD = False
SECURE_HSTS_SECONDS = 0 SECURE_HSTS_SECONDS = 0
SECURE_REDIRECT_EXEMPT = [] SECURE_REDIRECT_EXEMPT = []
SECURE_SSL_HOST = None SECURE_SSL_HOST = None

View File

@ -9,6 +9,7 @@ class SecurityMiddleware(MiddlewareMixin):
def __init__(self, get_response=None): def __init__(self, get_response=None):
self.sts_seconds = settings.SECURE_HSTS_SECONDS self.sts_seconds = settings.SECURE_HSTS_SECONDS
self.sts_include_subdomains = settings.SECURE_HSTS_INCLUDE_SUBDOMAINS self.sts_include_subdomains = settings.SECURE_HSTS_INCLUDE_SUBDOMAINS
self.sts_preload = settings.SECURE_HSTS_PRELOAD
self.content_type_nosniff = settings.SECURE_CONTENT_TYPE_NOSNIFF self.content_type_nosniff = settings.SECURE_CONTENT_TYPE_NOSNIFF
self.xss_filter = settings.SECURE_BROWSER_XSS_FILTER self.xss_filter = settings.SECURE_BROWSER_XSS_FILTER
self.redirect = settings.SECURE_SSL_REDIRECT self.redirect = settings.SECURE_SSL_REDIRECT
@ -30,10 +31,10 @@ class SecurityMiddleware(MiddlewareMixin):
if (self.sts_seconds and request.is_secure() and if (self.sts_seconds and request.is_secure() and
'strict-transport-security' not in response): 'strict-transport-security' not in response):
sts_header = "max-age=%s" % self.sts_seconds sts_header = "max-age=%s" % self.sts_seconds
if self.sts_include_subdomains: if self.sts_include_subdomains:
sts_header = sts_header + "; includeSubDomains" sts_header = sts_header + "; includeSubDomains"
if self.sts_preload:
sts_header = sts_header + "; preload"
response["strict-transport-security"] = sts_header response["strict-transport-security"] = sts_header
if self.content_type_nosniff and 'x-content-type-options' not in response: if self.content_type_nosniff and 'x-content-type-options' not in response:

View File

@ -226,6 +226,7 @@ enabled or disabled with a setting.
* :setting:`SECURE_BROWSER_XSS_FILTER` * :setting:`SECURE_BROWSER_XSS_FILTER`
* :setting:`SECURE_CONTENT_TYPE_NOSNIFF` * :setting:`SECURE_CONTENT_TYPE_NOSNIFF`
* :setting:`SECURE_HSTS_INCLUDE_SUBDOMAINS` * :setting:`SECURE_HSTS_INCLUDE_SUBDOMAINS`
* :setting:`SECURE_HSTS_PRELOAD`
* :setting:`SECURE_HSTS_SECONDS` * :setting:`SECURE_HSTS_SECONDS`
* :setting:`SECURE_REDIRECT_EXEMPT` * :setting:`SECURE_REDIRECT_EXEMPT`
* :setting:`SECURE_SSL_HOST` * :setting:`SECURE_SSL_HOST`
@ -260,6 +261,10 @@ to the ``Strict-Transport-Security`` header. This is recommended (assuming all
subdomains are served exclusively using HTTPS), otherwise your site may still subdomains are served exclusively using HTTPS), otherwise your site may still
be vulnerable via an insecure connection to a subdomain. be vulnerable via an insecure connection to a subdomain.
If you wish to submit your site to the `browser preload list`_, set the
:setting:`SECURE_HSTS_PRELOAD` setting to ``True``. That appends the
``preload`` directive to the ``Strict-Transport-Security`` header.
.. warning:: .. warning::
The HSTS policy applies to your entire domain, not just the URL of the The HSTS policy applies to your entire domain, not just the URL of the
response that you set the header on. Therefore, you should only use it if response that you set the header on. Therefore, you should only use it if
@ -277,6 +282,7 @@ be vulnerable via an insecure connection to a subdomain.
you may need to set the :setting:`SECURE_PROXY_SSL_HEADER` setting. you may need to set the :setting:`SECURE_PROXY_SSL_HEADER` setting.
.. _"Strict-Transport-Security" header: https://en.wikipedia.org/wiki/Strict_Transport_Security .. _"Strict-Transport-Security" header: https://en.wikipedia.org/wiki/Strict_Transport_Security
.. _browser preload list: https://hstspreload.appspot.com/
.. _x-content-type-options: .. _x-content-type-options:

View File

@ -2062,6 +2062,25 @@ non-zero value.
:setting:`SECURE_HSTS_SECONDS`) break your site. Read the :setting:`SECURE_HSTS_SECONDS`) break your site. Read the
:ref:`http-strict-transport-security` documentation first. :ref:`http-strict-transport-security` documentation first.
.. setting:: SECURE_HSTS_PRELOAD
``SECURE_HSTS_PRELOAD``
-----------------------
.. versionadded:: 1.11
Default: ``False``
If ``True``, the :class:`~django.middleware.security.SecurityMiddleware` adds
the ``preload`` directive to the :ref:`http-strict-transport-security`
header. It has no effect unless :setting:`SECURE_HSTS_SECONDS` is set to a
non-zero value.
.. warning::
Setting this incorrectly can irreversibly (for at least several months,
depending on browser releases) break your site. Read the
:ref:`http-strict-transport-security` documentation first.
.. setting:: SECURE_HSTS_SECONDS .. setting:: SECURE_HSTS_SECONDS
``SECURE_HSTS_SECONDS`` ``SECURE_HSTS_SECONDS``
@ -3334,6 +3353,7 @@ HTTP
* :setting:`SECURE_BROWSER_XSS_FILTER` * :setting:`SECURE_BROWSER_XSS_FILTER`
* :setting:`SECURE_CONTENT_TYPE_NOSNIFF` * :setting:`SECURE_CONTENT_TYPE_NOSNIFF`
* :setting:`SECURE_HSTS_INCLUDE_SUBDOMAINS` * :setting:`SECURE_HSTS_INCLUDE_SUBDOMAINS`
* :setting:`SECURE_HSTS_PRELOAD`
* :setting:`SECURE_HSTS_SECONDS` * :setting:`SECURE_HSTS_SECONDS`
* :setting:`SECURE_PROXY_SSL_HEADER` * :setting:`SECURE_PROXY_SSL_HEADER`
* :setting:`SECURE_REDIRECT_EXEMPT` * :setting:`SECURE_REDIRECT_EXEMPT`

View File

@ -229,6 +229,9 @@ Requests and Responses
* :class:`~django.middleware.common.CommonMiddleware` now sets the * :class:`~django.middleware.common.CommonMiddleware` now sets the
``Content-Length`` response header for non-streaming responses. ``Content-Length`` response header for non-streaming responses.
* Added the :setting:`SECURE_HSTS_PRELOAD` setting to allow appending the
``preload`` directive to the ``Strict-Transport-Security`` header.
Serialization Serialization
~~~~~~~~~~~~~ ~~~~~~~~~~~~~

View File

@ -160,8 +160,9 @@ server, there are some additional steps you may need:
to a particular site should always use HTTPS. Combined with redirecting to a particular site should always use HTTPS. Combined with redirecting
requests over HTTP to HTTPS, this will ensure that connections always enjoy requests over HTTP to HTTPS, this will ensure that connections always enjoy
the added security of SSL provided one successful connection has occurred. the added security of SSL provided one successful connection has occurred.
HSTS may either be configured with :setting:`SECURE_HSTS_SECONDS` and HSTS may either be configured with :setting:`SECURE_HSTS_SECONDS`,
:setting:`SECURE_HSTS_INCLUDE_SUBDOMAINS` or on the Web server. :setting:`SECURE_HSTS_INCLUDE_SUBDOMAINS`, and :setting:`SECURE_HSTS_PRELOAD`,
or on the Web server.
.. _host-headers-virtual-hosting: .. _host-headers-virtual-hosting:

View File

@ -99,6 +99,37 @@ class SecurityMiddlewareTest(SimpleTestCase):
response = self.process_response(secure=True) response = self.process_response(secure=True)
self.assertEqual(response["strict-transport-security"], "max-age=600") self.assertEqual(response["strict-transport-security"], "max-age=600")
@override_settings(SECURE_HSTS_SECONDS=10886400, SECURE_HSTS_PRELOAD=True)
def test_sts_preload(self):
"""
With HSTS_SECONDS non-zero and SECURE_HSTS_PRELOAD True, the middleware
adds a "strict-transport-security" header with the "preload" directive
to the response.
"""
response = self.process_response(secure=True)
self.assertEqual(response["strict-transport-security"], "max-age=10886400; preload")
@override_settings(SECURE_HSTS_SECONDS=10886400, SECURE_HSTS_INCLUDE_SUBDOMAINS=True, SECURE_HSTS_PRELOAD=True)
def test_sts_subdomains_and_preload(self):
"""
With HSTS_SECONDS non-zero, SECURE_HSTS_INCLUDE_SUBDOMAINS and
SECURE_HSTS_PRELOAD True, the middleware adds a "strict-transport-security"
header containing both the "includeSubDomains" and "preload" directives
to the response.
"""
response = self.process_response(secure=True)
self.assertEqual(response["strict-transport-security"], "max-age=10886400; includeSubDomains; preload")
@override_settings(SECURE_HSTS_SECONDS=10886400, SECURE_HSTS_PRELOAD=False)
def test_sts_no_preload(self):
"""
With HSTS_SECONDS non-zero and SECURE_HSTS_PRELOAD
False, the middleware adds a "strict-transport-security" header without
the "preload" directive to the response.
"""
response = self.process_response(secure=True)
self.assertEqual(response["strict-transport-security"], "max-age=10886400")
@override_settings(SECURE_CONTENT_TYPE_NOSNIFF=True) @override_settings(SECURE_CONTENT_TYPE_NOSNIFF=True)
def test_content_type_on(self): def test_content_type_on(self):
""" """