Fixed #33569 -- Added SECURE_PROXY_SSL_HEADER support for list of protocols in the header value.

This commit is contained in:
Thomas Schmidt 2022-03-07 17:25:52 -05:00 committed by Mariusz Felisiak
parent d46e158ee2
commit 1cf60ce601
4 changed files with 39 additions and 5 deletions

View File

@ -261,7 +261,8 @@ class HttpRequest:
)
header_value = self.META.get(header)
if header_value is not None:
return "https" if header_value == secure_value else "http"
header_value, *_ = header_value.split(",", 1)
return "https" if header_value.strip() == secure_value else "http"
return self._get_scheme()
def is_secure(self):

View File

@ -2442,8 +2442,17 @@ required value. For example::
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
This tells Django to trust the ``X-Forwarded-Proto`` header that comes from our
proxy, and any time its value is ``'https'``, then the request is guaranteed to
be secure (i.e., it originally came in via HTTPS).
proxy and that the request is guaranteed to be secure (i.e., it originally came
in via HTTPS) when:
* the header value is ``'https'``, or
* its initial, leftmost value is ``'https'`` in the case of a comma-separated
list of protocols (e.g. ``'https,http,http'``).
.. versionchanged:: 4.1
Support for a comma-separated list of protocols in the header value was
added.
You should *only* set this setting if you control your proxy or have some other
guarantee that it sets/strips this header appropriately.
@ -2463,8 +2472,9 @@ available in ``request.META``.)
* Your Django app is behind a proxy.
* Your proxy strips the ``X-Forwarded-Proto`` header from all incoming
requests. In other words, if end users include that header in their
requests, the proxy will discard it.
requests, even when it contains a comma-separated list of protocols. In
other words, if end users include that header in their requests, the
proxy will discard it.
* Your proxy sets the ``X-Forwarded-Proto`` header and sends it to Django,
but only for requests that originally come in via HTTPS.

View File

@ -293,6 +293,9 @@ Security
* The new :setting:`SECRET_KEY_FALLBACKS` setting allows providing a list of
values for secret key rotation.
* The :setting:`SECURE_PROXY_SSL_HEADER` setting now supports a comma-separated
list of protocols in the header value.
Serialization
~~~~~~~~~~~~~

View File

@ -424,6 +424,26 @@ class SecureProxySslHeaderTest(SimpleTestCase):
req.META["HTTP_X_FORWARDED_PROTO"] = "https"
self.assertIs(req.is_secure(), True)
@override_settings(SECURE_PROXY_SSL_HEADER=("HTTP_X_FORWARDED_PROTO", "https"))
def test_set_with_xheader_leftmost_right(self):
req = HttpRequest()
req.META["HTTP_X_FORWARDED_PROTO"] = "https, http"
self.assertIs(req.is_secure(), True)
req.META["HTTP_X_FORWARDED_PROTO"] = "https , http"
self.assertIs(req.is_secure(), True)
@override_settings(SECURE_PROXY_SSL_HEADER=("HTTP_X_FORWARDED_PROTO", "https"))
def test_set_with_xheader_leftmost_not_secure(self):
req = HttpRequest()
req.META["HTTP_X_FORWARDED_PROTO"] = "http, https"
self.assertIs(req.is_secure(), False)
@override_settings(SECURE_PROXY_SSL_HEADER=("HTTP_X_FORWARDED_PROTO", "https"))
def test_set_with_xheader_multiple_not_secure(self):
req = HttpRequest()
req.META["HTTP_X_FORWARDED_PROTO"] = "http ,wrongvalue,http,http"
self.assertIs(req.is_secure(), False)
@override_settings(SECURE_PROXY_SSL_HEADER=("HTTP_X_FORWARDED_PROTO", "https"))
def test_xheader_preferred_to_underlying_request(self):
class ProxyRequest(HttpRequest):