mirror of
https://github.com/django/django.git
synced 2025-05-06 06:56:30 +00:00
[2.2.x] Fixed CVE-2019-12781 -- Made HttpRequest always trust SECURE_PROXY_SSL_HEADER if set.
An HTTP request would not be redirected to HTTPS when the SECURE_PROXY_SSL_HEADER and SECURE_SSL_REDIRECT settings were used if the proxy connected to Django via HTTPS. HttpRequest.scheme will now always trust the SECURE_PROXY_SSL_HEADER if set, rather than falling back to the request scheme when the SECURE_PROXY_SSL_HEADER did not have the secure value. Thanks to Gavin Wahl for the report and initial patch suggestion, and Shai Berger for review. Backport of 54d0f5e62f54c29a12dd96f44bacd810cbe03ac8 from master
This commit is contained in:
parent
db9f7b44fc
commit
77706a3e47
@ -215,13 +215,14 @@ class HttpRequest:
|
|||||||
def scheme(self):
|
def scheme(self):
|
||||||
if settings.SECURE_PROXY_SSL_HEADER:
|
if settings.SECURE_PROXY_SSL_HEADER:
|
||||||
try:
|
try:
|
||||||
header, value = settings.SECURE_PROXY_SSL_HEADER
|
header, secure_value = settings.SECURE_PROXY_SSL_HEADER
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise ImproperlyConfigured(
|
raise ImproperlyConfigured(
|
||||||
'The SECURE_PROXY_SSL_HEADER setting must be a tuple containing two values.'
|
'The SECURE_PROXY_SSL_HEADER setting must be a tuple containing two values.'
|
||||||
)
|
)
|
||||||
if self.META.get(header) == value:
|
header_value = self.META.get(header)
|
||||||
return 'https'
|
if header_value is not None:
|
||||||
|
return 'https' if header_value == secure_value else 'http'
|
||||||
return self._get_scheme()
|
return self._get_scheme()
|
||||||
|
|
||||||
def is_secure(self):
|
def is_secure(self):
|
||||||
|
@ -2224,10 +2224,13 @@ By default, ``is_secure()`` determines if a request is secure by confirming
|
|||||||
that a requested URL uses ``https://``. This method is important for Django's
|
that a requested URL uses ``https://``. This method is important for Django's
|
||||||
CSRF protection, and it may be used by your own code or third-party apps.
|
CSRF protection, and it may be used by your own code or third-party apps.
|
||||||
|
|
||||||
If your Django app is behind a proxy, though, the proxy may be "swallowing" the
|
If your Django app is behind a proxy, though, the proxy may be "swallowing"
|
||||||
fact that a request is HTTPS, using a non-HTTPS connection between the proxy
|
whether the original request uses HTTPS or not. If there is a non-HTTPS
|
||||||
and Django. In this case, ``is_secure()`` would always return ``False`` -- even
|
connection between the proxy and Django then ``is_secure()`` would always
|
||||||
for requests that were made via HTTPS by the end user.
|
return ``False`` -- even for requests that were made via HTTPS by the end user.
|
||||||
|
In contrast, if there is an HTTPS connection between the proxy and Django then
|
||||||
|
``is_secure()`` would always return ``True`` -- even for requests that were
|
||||||
|
made originally via HTTP.
|
||||||
|
|
||||||
In this situation, configure your proxy to set a custom HTTP header that tells
|
In this situation, configure your proxy to set a custom HTTP header that tells
|
||||||
Django whether the request came in via HTTPS, and set
|
Django whether the request came in via HTTPS, and set
|
||||||
|
@ -5,3 +5,23 @@ Django 1.11.22 release notes
|
|||||||
*July 1, 2019*
|
*July 1, 2019*
|
||||||
|
|
||||||
Django 1.11.22 fixes a security issue in 1.11.21.
|
Django 1.11.22 fixes a security issue in 1.11.21.
|
||||||
|
|
||||||
|
CVE-2019-12781: Incorrect HTTP detection with reverse-proxy connecting via HTTPS
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
When deployed behind a reverse-proxy connecting to Django via HTTPS,
|
||||||
|
:attr:`django.http.HttpRequest.scheme` would incorrectly detect client
|
||||||
|
requests made via HTTP as using HTTPS. This entails incorrect results for
|
||||||
|
:meth:`~django.http.HttpRequest.is_secure`, and
|
||||||
|
:meth:`~django.http.HttpRequest.build_absolute_uri`, and that HTTP
|
||||||
|
requests would not be redirected to HTTPS in accordance with
|
||||||
|
:setting:`SECURE_SSL_REDIRECT`.
|
||||||
|
|
||||||
|
``HttpRequest.scheme`` now respects :setting:`SECURE_PROXY_SSL_HEADER`, if it
|
||||||
|
is configured, and the appropriate header is set on the request, for both HTTP
|
||||||
|
and HTTPS requests.
|
||||||
|
|
||||||
|
If you deploy Django behind a reverse-proxy that forwards HTTP requests, and
|
||||||
|
that connects to Django via HTTPS, be sure to verify that your application
|
||||||
|
correctly handles code paths relying on ``scheme``, ``is_secure()``,
|
||||||
|
``build_absolute_uri()``, and ``SECURE_SSL_REDIRECT``.
|
||||||
|
@ -5,3 +5,23 @@ Django 2.1.10 release notes
|
|||||||
*July 1, 2019*
|
*July 1, 2019*
|
||||||
|
|
||||||
Django 2.1.10 fixes a security issue in 2.1.9.
|
Django 2.1.10 fixes a security issue in 2.1.9.
|
||||||
|
|
||||||
|
CVE-2019-12781: Incorrect HTTP detection with reverse-proxy connecting via HTTPS
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
When deployed behind a reverse-proxy connecting to Django via HTTPS,
|
||||||
|
:attr:`django.http.HttpRequest.scheme` would incorrectly detect client
|
||||||
|
requests made via HTTP as using HTTPS. This entails incorrect results for
|
||||||
|
:meth:`~django.http.HttpRequest.is_secure`, and
|
||||||
|
:meth:`~django.http.HttpRequest.build_absolute_uri`, and that HTTP
|
||||||
|
requests would not be redirected to HTTPS in accordance with
|
||||||
|
:setting:`SECURE_SSL_REDIRECT`.
|
||||||
|
|
||||||
|
``HttpRequest.scheme`` now respects :setting:`SECURE_PROXY_SSL_HEADER`, if it
|
||||||
|
is configured, and the appropriate header is set on the request, for both HTTP
|
||||||
|
and HTTPS requests.
|
||||||
|
|
||||||
|
If you deploy Django behind a reverse-proxy that forwards HTTP requests, and
|
||||||
|
that connects to Django via HTTPS, be sure to verify that your application
|
||||||
|
correctly handles code paths relying on ``scheme``, ``is_secure()``,
|
||||||
|
``build_absolute_uri()``, and ``SECURE_SSL_REDIRECT``.
|
||||||
|
@ -4,8 +4,28 @@ Django 2.2.3 release notes
|
|||||||
|
|
||||||
*Expected July 1, 2019*
|
*Expected July 1, 2019*
|
||||||
|
|
||||||
Django 2.2.3 fixes several bugs in 2.2.2. Also, the latest string translations
|
Django 2.2.3 fixes a security issue and several bugs in 2.2.2. Also, the latest
|
||||||
from Transifex are incorporated.
|
string translations from Transifex are incorporated.
|
||||||
|
|
||||||
|
CVE-2019-12781: Incorrect HTTP detection with reverse-proxy connecting via HTTPS
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
When deployed behind a reverse-proxy connecting to Django via HTTPS,
|
||||||
|
:attr:`django.http.HttpRequest.scheme` would incorrectly detect client
|
||||||
|
requests made via HTTP as using HTTPS. This entails incorrect results for
|
||||||
|
:meth:`~django.http.HttpRequest.is_secure`, and
|
||||||
|
:meth:`~django.http.HttpRequest.build_absolute_uri`, and that HTTP
|
||||||
|
requests would not be redirected to HTTPS in accordance with
|
||||||
|
:setting:`SECURE_SSL_REDIRECT`.
|
||||||
|
|
||||||
|
``HttpRequest.scheme`` now respects :setting:`SECURE_PROXY_SSL_HEADER`, if it is
|
||||||
|
configured, and the appropriate header is set on the request, for both HTTP and
|
||||||
|
HTTPS requests.
|
||||||
|
|
||||||
|
If you deploy Django behind a reverse-proxy that forwards HTTP requests, and
|
||||||
|
that connects to Django via HTTPS, be sure to verify that your application
|
||||||
|
correctly handles code paths relying on ``scheme``, ``is_secure()``,
|
||||||
|
``build_absolute_uri()``, and ``SECURE_SSL_REDIRECT``.
|
||||||
|
|
||||||
Bugfixes
|
Bugfixes
|
||||||
========
|
========
|
||||||
|
@ -367,6 +367,18 @@ class SecureProxySslHeaderTest(SimpleTestCase):
|
|||||||
req.META['HTTP_X_FORWARDED_PROTOCOL'] = 'https'
|
req.META['HTTP_X_FORWARDED_PROTOCOL'] = 'https'
|
||||||
self.assertIs(req.is_secure(), True)
|
self.assertIs(req.is_secure(), True)
|
||||||
|
|
||||||
|
@override_settings(SECURE_PROXY_SSL_HEADER=('HTTP_X_FORWARDED_PROTOCOL', 'https'))
|
||||||
|
def test_xheader_preferred_to_underlying_request(self):
|
||||||
|
class ProxyRequest(HttpRequest):
|
||||||
|
def _get_scheme(self):
|
||||||
|
"""Proxy always connecting via HTTPS"""
|
||||||
|
return 'https'
|
||||||
|
|
||||||
|
# Client connects via HTTP.
|
||||||
|
req = ProxyRequest()
|
||||||
|
req.META['HTTP_X_FORWARDED_PROTOCOL'] = 'http'
|
||||||
|
self.assertIs(req.is_secure(), False)
|
||||||
|
|
||||||
|
|
||||||
class IsOverriddenTest(SimpleTestCase):
|
class IsOverriddenTest(SimpleTestCase):
|
||||||
def test_configure(self):
|
def test_configure(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user