Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c613af4

Browse files
committed
[1.2.X] Added protection against spoofing of X_FORWARDED_HOST headers. A security announcement will be made shortly.
Backport of r16758 from trunk. git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@16764 bcc190cf-cafb-0310-a4f2-bffc1f526a37
1 parent 285b464 commit c613af4

File tree

5 files changed

+112
-5
lines changed

5 files changed

+112
-5
lines changed

django/conf/global_settings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,8 @@
390390
DEFAULT_TABLESPACE = ''
391391
DEFAULT_INDEX_TABLESPACE = ''
392392

393+
USE_X_FORWARDED_HOST = False
394+
393395
##############
394396
# MIDDLEWARE #
395397
##############

django/http/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ def __repr__(self):
4545
def get_host(self):
4646
"""Returns the HTTP host using the environment or request headers."""
4747
# We try three options, in order of decreasing preference.
48-
if 'HTTP_X_FORWARDED_HOST' in self.META:
48+
if settings.USE_X_FORWARDED_HOST and (
49+
'HTTP_X_FORWARDED_HOST' in self.META):
4950
host = self.META['HTTP_X_FORWARDED_HOST']
5051
elif 'HTTP_HOST' in self.META:
5152
host = self.META['HTTP_HOST']

docs/ref/request-response.txt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,11 @@ Methods
185185

186186
.. method:: HttpRequest.get_host()
187187

188-
Returns the originating host of the request using information from the
189-
``HTTP_X_FORWARDED_HOST`` and ``HTTP_HOST`` headers (in that order). If
190-
they don't provide a value, the method uses a combination of
191-
``SERVER_NAME`` and ``SERVER_PORT`` as detailed in `PEP 333`_.
188+
Returns the originating host of the request using information from
189+
the ``HTTP_X_FORWARDED_HOST`` (if enabled in the settings) and ``HTTP_HOST``
190+
headers (in that order). If they don't provide a value, the method
191+
uses a combination of ``SERVER_NAME`` and ``SERVER_PORT`` as
192+
detailed in :pep:`3333`.
192193

193194
.. _PEP 333: http://www.python.org/dev/peps/pep-0333/
194195

docs/ref/settings.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1698,6 +1698,19 @@ and ``NUMBER_GROUPING`` from current locale, to format the number.
16981698

16991699
See also ``THOUSAND_SEPARATOR`` and ``NUMBER_GROUPING``.
17001700

1701+
.. setting:: USE_X_FORWARDED_HOST
1702+
1703+
USE_X_FORWARDED_HOST
1704+
--------------------
1705+
1706+
.. versionadded:: 1.3.1
1707+
1708+
Default: ``False``
1709+
1710+
A boolean that specifies whether to use the X-Forwarded-Host header in
1711+
preference to the Host header. This should only be enabled if a proxy
1712+
which sets this header is in use.
1713+
17011714
.. setting:: YEAR_MONTH_FORMAT
17021715

17031716
YEAR_MONTH_FORMAT

tests/regressiontests/requests/tests.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22
import time
33
import unittest
44

5+
from django.conf import settings
56
from django.http import HttpRequest, HttpResponse, parse_cookie
67
from django.core.handlers.wsgi import WSGIRequest
78
from django.core.handlers.modpython import ModPythonRequest
89
from django.utils.http import cookie_date
910

11+
1012
class RequestsTests(unittest.TestCase):
1113

1214
def test_httprequest(self):
@@ -57,3 +59,91 @@ def test_httprequest_location(self):
5759
request.path = ''
5860
self.assertEqual(request.build_absolute_uri(location="/path/with:colons"),
5961
'http://www.example.com/path/with:colons')
62+
63+
def test_http_get_host(self):
64+
old_USE_X_FORWARDED_HOST = settings.USE_X_FORWARDED_HOST
65+
try:
66+
settings.USE_X_FORWARDED_HOST = False
67+
68+
# Check if X_FORWARDED_HOST is provided.
69+
request = HttpRequest()
70+
request.META = {
71+
u'HTTP_X_FORWARDED_HOST': u'forward.com',
72+
u'HTTP_HOST': u'example.com',
73+
u'SERVER_NAME': u'internal.com',
74+
u'SERVER_PORT': 80,
75+
}
76+
# X_FORWARDED_HOST is ignored.
77+
self.assertEqual(request.get_host(), 'example.com')
78+
79+
# Check if X_FORWARDED_HOST isn't provided.
80+
request = HttpRequest()
81+
request.META = {
82+
u'HTTP_HOST': u'example.com',
83+
u'SERVER_NAME': u'internal.com',
84+
u'SERVER_PORT': 80,
85+
}
86+
self.assertEqual(request.get_host(), 'example.com')
87+
88+
# Check if HTTP_HOST isn't provided.
89+
request = HttpRequest()
90+
request.META = {
91+
u'SERVER_NAME': u'internal.com',
92+
u'SERVER_PORT': 80,
93+
}
94+
self.assertEqual(request.get_host(), 'internal.com')
95+
96+
# Check if HTTP_HOST isn't provided, and we're on a nonstandard port
97+
request = HttpRequest()
98+
request.META = {
99+
u'SERVER_NAME': u'internal.com',
100+
u'SERVER_PORT': 8042,
101+
}
102+
self.assertEqual(request.get_host(), 'internal.com:8042')
103+
104+
finally:
105+
settings.USE_X_FORWARDED_HOST = old_USE_X_FORWARDED_HOST
106+
107+
def test_http_get_host_with_x_forwarded_host(self):
108+
old_USE_X_FORWARDED_HOST = settings.USE_X_FORWARDED_HOST
109+
try:
110+
settings.USE_X_FORWARDED_HOST = True
111+
112+
# Check if X_FORWARDED_HOST is provided.
113+
request = HttpRequest()
114+
request.META = {
115+
u'HTTP_X_FORWARDED_HOST': u'forward.com',
116+
u'HTTP_HOST': u'example.com',
117+
u'SERVER_NAME': u'internal.com',
118+
u'SERVER_PORT': 80,
119+
}
120+
# X_FORWARDED_HOST is obeyed.
121+
self.assertEqual(request.get_host(), 'forward.com')
122+
123+
# Check if X_FORWARDED_HOST isn't provided.
124+
request = HttpRequest()
125+
request.META = {
126+
u'HTTP_HOST': u'example.com',
127+
u'SERVER_NAME': u'internal.com',
128+
u'SERVER_PORT': 80,
129+
}
130+
self.assertEqual(request.get_host(), 'example.com')
131+
132+
# Check if HTTP_HOST isn't provided.
133+
request = HttpRequest()
134+
request.META = {
135+
u'SERVER_NAME': u'internal.com',
136+
u'SERVER_PORT': 80,
137+
}
138+
self.assertEqual(request.get_host(), 'internal.com')
139+
140+
# Check if HTTP_HOST isn't provided, and we're on a nonstandard port
141+
request = HttpRequest()
142+
request.META = {
143+
u'SERVER_NAME': u'internal.com',
144+
u'SERVER_PORT': 8042,
145+
}
146+
self.assertEqual(request.get_host(), 'internal.com:8042')
147+
148+
finally:
149+
settings.USE_X_FORWARDED_HOST = old_USE_X_FORWARDED_HOST

0 commit comments

Comments
 (0)