mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
				
					committed by
					
						 Mariusz Felisiak
						Mariusz Felisiak
					
				
			
			
				
	
			
			
			
						parent
						
							30b3ee9d0b
						
					
				
				
					commit
					54d0f5e62f
				
			| @@ -226,13 +226,14 @@ class HttpRequest: | ||||
|     def scheme(self): | ||||
|         if settings.SECURE_PROXY_SSL_HEADER: | ||||
|             try: | ||||
|                 header, value = settings.SECURE_PROXY_SSL_HEADER | ||||
|                 header, secure_value = settings.SECURE_PROXY_SSL_HEADER | ||||
|             except ValueError: | ||||
|                 raise ImproperlyConfigured( | ||||
|                     'The SECURE_PROXY_SSL_HEADER setting must be a tuple containing two values.' | ||||
|                 ) | ||||
|             if self.META.get(header) == value: | ||||
|                 return 'https' | ||||
|             header_value = self.META.get(header) | ||||
|             if header_value is not None: | ||||
|                 return 'https' if header_value == secure_value else 'http' | ||||
|         return self._get_scheme() | ||||
|  | ||||
|     def is_secure(self): | ||||
|   | ||||
| @@ -2253,10 +2253,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 | ||||
| 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 | ||||
| fact that a request is HTTPS, using a non-HTTPS connection between the proxy | ||||
| and Django. In this case, ``is_secure()`` would always return ``False`` -- even | ||||
| for requests that were made via HTTPS by the end user. | ||||
| If your Django app is behind a proxy, though, the proxy may be "swallowing" | ||||
| whether the original request uses HTTPS or not. If there is a non-HTTPS | ||||
| connection between the proxy and Django then ``is_secure()`` would always | ||||
| 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 | ||||
| Django whether the request came in via HTTPS, and set | ||||
|   | ||||
| @@ -5,3 +5,23 @@ Django 1.11.22 release notes | ||||
| *July 1, 2019* | ||||
|  | ||||
| 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* | ||||
|  | ||||
| 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* | ||||
|  | ||||
| Django 2.2.3 fixes several bugs in 2.2.2. Also, the latest string translations | ||||
| from Transifex are incorporated. | ||||
| Django 2.2.3 fixes a security issue and several bugs in 2.2.2. Also, the latest | ||||
| 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 | ||||
| ======== | ||||
|   | ||||
| @@ -378,6 +378,18 @@ class SecureProxySslHeaderTest(SimpleTestCase): | ||||
|         req.META['HTTP_X_FORWARDED_PROTOCOL'] = 'https' | ||||
|         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): | ||||
|     def test_configure(self): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user