File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -199,13 +199,14 @@ def _get_scheme(self):
199199 def scheme (self ):
200200 if settings .SECURE_PROXY_SSL_HEADER :
201201 try :
202- header , value = settings .SECURE_PROXY_SSL_HEADER
202+ header , secure_value = settings .SECURE_PROXY_SSL_HEADER
203203 except ValueError :
204204 raise ImproperlyConfigured (
205205 'The SECURE_PROXY_SSL_HEADER setting must be a tuple containing two values.'
206206 )
207- if self .META .get (header ) == value :
208- return 'https'
207+ header_value = self .META .get (header )
208+ if header_value is not None :
209+ return 'https' if header_value == secure_value else 'http'
209210 return self ._get_scheme ()
210211
211212 def is_secure (self ):
Original file line number Diff line number Diff line change @@ -2189,10 +2189,13 @@ whether a request is secure by looking at whether the requested URL uses
21892189"https://". This is important for Django's CSRF protection, and may be used
21902190by your own code or third-party apps.
21912191
2192- If your Django app is behind a proxy, though, the proxy may be "swallowing" the
2193- fact that a request is HTTPS, using a non-HTTPS connection between the proxy
2194- and Django. In this case, ``is_secure()`` would always return ``False`` -- even
2195- for requests that were made via HTTPS by the end user.
2192+ If your Django app is behind a proxy, though, the proxy may be "swallowing"
2193+ whether the original request uses HTTPS or not. If there is a non-HTTPS
2194+ connection between the proxy and Django then ``is_secure()`` would always
2195+ return ``False`` -- even for requests that were made via HTTPS by the end user.
2196+ In contrast, if there is an HTTPS connection between the proxy and Django then
2197+ ``is_secure()`` would always return ``True`` -- even for requests that were
2198+ made originally via HTTP.
21962199
21972200In this situation, you'll want to configure your proxy to set a custom HTTP
21982201header that tells Django whether the request came in via HTTPS, and you'll want
Original file line number Diff line number Diff line change @@ -5,3 +5,23 @@ Django 1.11.22 release notes
55*July 1, 2019*
66
77Django 1.11.22 fixes a security issue in 1.11.21.
8+
9+ CVE-2019-12781: Incorrect HTTP detection with reverse-proxy connecting via HTTPS
10+ --------------------------------------------------------------------------------
11+
12+ When deployed behind a reverse-proxy connecting to Django via HTTPS,
13+ :attr:`django.http.HttpRequest.scheme` would incorrectly detect client
14+ requests made via HTTP as using HTTPS. This entails incorrect results for
15+ :meth:`~django.http.HttpRequest.is_secure`, and
16+ :meth:`~django.http.HttpRequest.build_absolute_uri`, and that HTTP
17+ requests would not be redirected to HTTPS in accordance with
18+ :setting:`SECURE_SSL_REDIRECT`.
19+
20+ ``HttpRequest.scheme`` now respects :setting:`SECURE_PROXY_SSL_HEADER`, if it
21+ is configured, and the appropriate header is set on the request, for both HTTP
22+ and HTTPS requests.
23+
24+ If you deploy Django behind a reverse-proxy that forwards HTTP requests, and
25+ that connects to Django via HTTPS, be sure to verify that your application
26+ correctly handles code paths relying on ``scheme``, ``is_secure()``,
27+ ``build_absolute_uri()``, and ``SECURE_SSL_REDIRECT``.
Original file line number Diff line number Diff line change @@ -334,6 +334,18 @@ def test_set_with_xheader_right(self):
334334 req .META ['HTTP_X_FORWARDED_PROTOCOL' ] = 'https'
335335 self .assertIs (req .is_secure (), True )
336336
337+ @override_settings (SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL' , 'https' ))
338+ def test_xheader_preferred_to_underlying_request (self ):
339+ class ProxyRequest (HttpRequest ):
340+ def _get_scheme (self ):
341+ """Proxy always connecting via HTTPS"""
342+ return 'https'
343+
344+ # Client connects via HTTP.
345+ req = ProxyRequest ()
346+ req .META ['HTTP_X_FORWARDED_PROTOCOL' ] = 'http'
347+ self .assertIs (req .is_secure (), False )
348+
337349
338350class IsOverriddenTest (SimpleTestCase ):
339351 def test_configure (self ):
You can’t perform that action at this time.
0 commit comments