+95
-22
lines changedFilter options
+95
-22
lines changed Original file line number Diff line number Diff line change
@@ -96,12 +96,13 @@ def get_host(self):
96
96
"""Return the HTTP host using the environment or request headers."""
97
97
host = self._get_raw_host()
98
98
99
-
# There is no hostname validation when DEBUG=True
100
-
if settings.DEBUG:
101
-
return host
99
+
# Allow variants of localhost if ALLOWED_HOSTS is empty and DEBUG=True.
100
+
allowed_hosts = settings.ALLOWED_HOSTS
101
+
if settings.DEBUG and not allowed_hosts:
102
+
allowed_hosts = ['localhost', '127.0.0.1', '[::1]']
102
103
103
104
domain, port = split_domain_port(host)
104
-
if domain and validate_host(domain, settings.ALLOWED_HOSTS):
105
+
if domain and validate_host(domain, allowed_hosts):
105
106
return host
106
107
else:
107
108
msg = "Invalid HTTP_HOST header: %r." % host
Original file line number Diff line number Diff line change
@@ -90,14 +90,19 @@ If the ``Host`` header (or ``X-Forwarded-Host`` if
90
90
list, the :meth:`django.http.HttpRequest.get_host()` method will raise
91
91
:exc:`~django.core.exceptions.SuspiciousOperation`.
92
92
93
-
When :setting:`DEBUG` is ``True`` or when running tests, host validation is
94
-
disabled; any host will be accepted. Thus it's usually only necessary to set it
95
-
in production.
93
+
When :setting:`DEBUG` is ``True`` and ``ALLOWED_HOSTS`` is empty, the host
94
+
is validated against ``['localhost', '127.0.0.1', '[::1]']``.
96
95
97
96
This validation only applies via :meth:`~django.http.HttpRequest.get_host()`;
98
97
if your code accesses the ``Host`` header directly from ``request.META`` you
99
98
are bypassing this security protection.
100
99
100
+
.. versionchanged:: 1.10.3
101
+
102
+
In older versions, ``ALLOWED_HOSTS`` wasn't checked if ``DEBUG=True``.
103
+
This was also changed in Django 1.9.11 and 1.8.16 to prevent a
104
+
DNS rebinding attack.
105
+
101
106
.. setting:: APPEND_SLASH
102
107
103
108
``APPEND_SLASH``
Original file line number Diff line number Diff line change
@@ -20,6 +20,28 @@ the ``manage.py test --keepdb`` option or if the user has an active session
20
20
21
21
A randomly generated password is now used for each test run.
22
22
23
+
DNS rebinding vulnerability when ``DEBUG=True``
24
+
===============================================
25
+
26
+
Older versions of Django don't validate the ``Host`` header against
27
+
``settings.ALLOWED_HOSTS`` when ``settings.DEBUG=True``. This makes them
28
+
vulnerable to a `DNS rebinding attack
29
+
<http://benmmurphy.github.io/blog/2016/07/11/rails-webconsole-dns-rebinding/>`_.
30
+
31
+
While Django doesn't ship a module that allows remote code execution, this is
32
+
at least a cross-site scripting vector, which could be quite serious if
33
+
developers load a copy of the production database in development or connect to
34
+
some production services for which there's no development instance, for
35
+
example. If a project uses a package like the ``django-debug-toolbar``, then
36
+
the attacker could execute arbitrary SQL, which could be especially bad if the
37
+
developers connect to the database with a superuser account.
38
+
39
+
``settings.ALLOWED_HOSTS`` is now validated regardless of ``DEBUG``. For
40
+
convenience, if ``ALLOWED_HOSTS`` is empty and ``DEBUG=True``, the following
41
+
variations of localhost are allowed ``['localhost', '127.0.0.1', '::1']``. If
42
+
your local settings file has your production ``ALLOWED_HOSTS`` value, you must
43
+
now omit it to get those fallback values.
44
+
23
45
Bugfixes
24
46
========
25
47
Original file line number Diff line number Diff line change
@@ -19,3 +19,25 @@ the ``manage.py test --keepdb`` option or if the user has an active session
19
19
(such as an attacker's connection).
20
20
21
21
A randomly generated password is now used for each test run.
22
+
23
+
DNS rebinding vulnerability when ``DEBUG=True``
24
+
===============================================
25
+
26
+
Older versions of Django don't validate the ``Host`` header against
27
+
``settings.ALLOWED_HOSTS`` when ``settings.DEBUG=True``. This makes them
28
+
vulnerable to a `DNS rebinding attack
29
+
<http://benmmurphy.github.io/blog/2016/07/11/rails-webconsole-dns-rebinding/>`_.
30
+
31
+
While Django doesn't ship a module that allows remote code execution, this is
32
+
at least a cross-site scripting vector, which could be quite serious if
33
+
developers load a copy of the production database in development or connect to
34
+
some production services for which there's no development instance, for
35
+
example. If a project uses a package like the ``django-debug-toolbar``, then
36
+
the attacker could execute arbitrary SQL, which could be especially bad if the
37
+
developers connect to the database with a superuser account.
38
+
39
+
``settings.ALLOWED_HOSTS`` is now validated regardless of ``DEBUG``. For
40
+
convenience, if ``ALLOWED_HOSTS`` is empty and ``DEBUG=True``, the following
41
+
variations of localhost are allowed ``['localhost', '127.0.0.1', '::1']``. If
42
+
your local settings file has your production ``ALLOWED_HOSTS`` value, you must
43
+
now omit it to get those fallback values.
Original file line number Diff line number Diff line change
@@ -19,3 +19,25 @@ the ``manage.py test --keepdb`` option or if the user has an active session
19
19
(such as an attacker's connection).
20
20
21
21
A randomly generated password is now used for each test run.
22
+
23
+
DNS rebinding vulnerability when ``DEBUG=True``
24
+
===============================================
25
+
26
+
Older versions of Django don't validate the ``Host`` header against
27
+
``settings.ALLOWED_HOSTS`` when ``settings.DEBUG=True``. This makes them
28
+
vulnerable to a `DNS rebinding attack
29
+
<http://benmmurphy.github.io/blog/2016/07/11/rails-webconsole-dns-rebinding/>`_.
30
+
31
+
While Django doesn't ship a module that allows remote code execution, this is
32
+
at least a cross-site scripting vector, which could be quite serious if
33
+
developers load a copy of the production database in development or connect to
34
+
some production services for which there's no development instance, for
35
+
example. If a project uses a package like the ``django-debug-toolbar``, then
36
+
the attacker could execute arbitrary SQL, which could be especially bad if the
37
+
developers connect to the database with a superuser account.
38
+
39
+
``settings.ALLOWED_HOSTS`` is now validated regardless of ``DEBUG``. For
40
+
convenience, if ``ALLOWED_HOSTS`` is empty and ``DEBUG=True``, the following
41
+
variations of localhost are allowed ``['localhost', '127.0.0.1', '::1']``. If
42
+
your local settings file has your production ``ALLOWED_HOSTS`` value, you must
43
+
now omit it to get those fallback values.
Original file line number Diff line number Diff line change
@@ -377,7 +377,7 @@ def test_bare_secret_accepted_and_replaced(self):
377
377
self.assertEqual(len(csrf_cookie.value), CSRF_TOKEN_LENGTH)
378
378
self._check_token_present(resp, csrf_id=csrf_cookie.value)
379
379
380
-
@override_settings(DEBUG=True)
380
+
@override_settings(DEBUG=True, ALLOWED_HOSTS=['www.example.com'])
381
381
def test_https_bad_referer(self):
382
382
"""
383
383
Test that a POST HTTPS request with a bad referer is rejected
Original file line number Diff line number Diff line change
@@ -756,21 +756,22 @@ def test_get_port_with_x_forwarded_port(self):
756
756
self.assertEqual(request.get_port(), '8080')
757
757
758
758
@override_settings(DEBUG=True, ALLOWED_HOSTS=[])
759
-
def test_host_validation_disabled_in_debug_mode(self):
760
-
"""If ALLOWED_HOSTS is empty and DEBUG is True, all hosts pass."""
761
-
request = HttpRequest()
762
-
request.META = {
763
-
'HTTP_HOST': 'example.com',
764
-
}
765
-
self.assertEqual(request.get_host(), 'example.com')
759
+
def test_host_validation_in_debug_mode(self):
760
+
"""
761
+
If ALLOWED_HOSTS is empty and DEBUG is True, variants of localhost are
762
+
allowed.
763
+
"""
764
+
valid_hosts = ['localhost', '127.0.0.1', '[::1]']
765
+
for host in valid_hosts:
766
+
request = HttpRequest()
767
+
request.META = {'HTTP_HOST': host}
768
+
self.assertEqual(request.get_host(), host)
766
769
767
-
# Invalid hostnames would normally raise a SuspiciousOperation,
768
-
# but we have DEBUG=True, so this check is disabled.
769
-
request = HttpRequest()
770
-
request.META = {
771
-
'HTTP_HOST': "invalid_hostname.com",
772
-
}
773
-
self.assertEqual(request.get_host(), "invalid_hostname.com")
770
+
# Other hostnames raise a SuspiciousOperation.
771
+
with self.assertRaises(SuspiciousOperation):
772
+
request = HttpRequest()
773
+
request.META = {'HTTP_HOST': 'example.com'}
774
+
request.get_host()
774
775
775
776
@override_settings(ALLOWED_HOSTS=[])
776
777
def test_get_host_suggestion_of_allowed_host(self):
You can’t perform that action at this time.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4