Fixed #33569 -- Added SECURE_PROXY_SSL_HEADER support for list of protocols in the header value.
This commit is contained in:
parent
d46e158ee2
commit
1cf60ce601
|
@ -261,7 +261,8 @@ class HttpRequest:
|
||||||
)
|
)
|
||||||
header_value = self.META.get(header)
|
header_value = self.META.get(header)
|
||||||
if header_value is not None:
|
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()
|
return self._get_scheme()
|
||||||
|
|
||||||
def is_secure(self):
|
def is_secure(self):
|
||||||
|
|
|
@ -2442,8 +2442,17 @@ required value. For example::
|
||||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||||
|
|
||||||
This tells Django to trust the ``X-Forwarded-Proto`` header that comes from our
|
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
|
proxy and that the request is guaranteed to be secure (i.e., it originally came
|
||||||
be secure (i.e., it originally came in via HTTPS).
|
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
|
You should *only* set this setting if you control your proxy or have some other
|
||||||
guarantee that it sets/strips this header appropriately.
|
guarantee that it sets/strips this header appropriately.
|
||||||
|
@ -2463,8 +2472,9 @@ available in ``request.META``.)
|
||||||
|
|
||||||
* Your Django app is behind a proxy.
|
* Your Django app is behind a proxy.
|
||||||
* Your proxy strips the ``X-Forwarded-Proto`` header from all incoming
|
* Your proxy strips the ``X-Forwarded-Proto`` header from all incoming
|
||||||
requests. In other words, if end users include that header in their
|
requests, even when it contains a comma-separated list of protocols. In
|
||||||
requests, the proxy will discard it.
|
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,
|
* Your proxy sets the ``X-Forwarded-Proto`` header and sends it to Django,
|
||||||
but only for requests that originally come in via HTTPS.
|
but only for requests that originally come in via HTTPS.
|
||||||
|
|
||||||
|
|
|
@ -293,6 +293,9 @@ Security
|
||||||
* The new :setting:`SECRET_KEY_FALLBACKS` setting allows providing a list of
|
* The new :setting:`SECRET_KEY_FALLBACKS` setting allows providing a list of
|
||||||
values for secret key rotation.
|
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
|
Serialization
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -424,6 +424,26 @@ class SecureProxySslHeaderTest(SimpleTestCase):
|
||||||
req.META["HTTP_X_FORWARDED_PROTO"] = "https"
|
req.META["HTTP_X_FORWARDED_PROTO"] = "https"
|
||||||
self.assertIs(req.is_secure(), True)
|
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"))
|
@override_settings(SECURE_PROXY_SSL_HEADER=("HTTP_X_FORWARDED_PROTO", "https"))
|
||||||
def test_xheader_preferred_to_underlying_request(self):
|
def test_xheader_preferred_to_underlying_request(self):
|
||||||
class ProxyRequest(HttpRequest):
|
class ProxyRequest(HttpRequest):
|
||||||
|
|
Loading…
Reference in New Issue