[1.3.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.3.X@16761 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
afe47636f7
commit
2f7fadc38e
@ -399,6 +399,8 @@ URL_VALIDATOR_USER_AGENT = "Django/%s (http://www.djangoproject.com)" % get_vers
|
||||
DEFAULT_TABLESPACE = ''
|
||||
DEFAULT_INDEX_TABLESPACE = ''
|
||||
|
||||
USE_X_FORWARDED_HOST = False
|
||||
|
||||
##############
|
||||
# MIDDLEWARE #
|
||||
##############
|
||||
|
@ -153,7 +153,8 @@ class HttpRequest(object):
|
||||
def get_host(self):
|
||||
"""Returns the HTTP host using the environment or request headers."""
|
||||
# We try three options, in order of decreasing preference.
|
||||
if 'HTTP_X_FORWARDED_HOST' in self.META:
|
||||
if settings.USE_X_FORWARDED_HOST and (
|
||||
'HTTP_X_FORWARDED_HOST' in self.META):
|
||||
host = self.META['HTTP_X_FORWARDED_HOST']
|
||||
elif 'HTTP_HOST' in self.META:
|
||||
host = self.META['HTTP_HOST']
|
||||
|
@ -191,10 +191,11 @@ Methods
|
||||
|
||||
.. method:: HttpRequest.get_host()
|
||||
|
||||
Returns the originating host of the request using information from the
|
||||
``HTTP_X_FORWARDED_HOST`` and ``HTTP_HOST`` headers (in that order). If
|
||||
they don't provide a value, the method uses a combination of
|
||||
``SERVER_NAME`` and ``SERVER_PORT`` as detailed in `PEP 333`_.
|
||||
Returns the originating host of the request using information from
|
||||
the ``HTTP_X_FORWARDED_HOST`` (if enabled in the settings) and ``HTTP_HOST``
|
||||
headers (in that order). If they don't provide a value, the method
|
||||
uses a combination of ``SERVER_NAME`` and ``SERVER_PORT`` as
|
||||
detailed in :pep:`3333`.
|
||||
|
||||
.. _PEP 333: http://www.python.org/dev/peps/pep-0333/
|
||||
|
||||
|
@ -1960,6 +1960,19 @@ in order to format numbers.
|
||||
|
||||
See also :setting:`THOUSAND_SEPARATOR` and :setting:`NUMBER_GROUPING`.
|
||||
|
||||
.. setting:: USE_X_FORWARDED_HOST
|
||||
|
||||
USE_X_FORWARDED_HOST
|
||||
--------------------
|
||||
|
||||
.. versionadded:: 1.3.1
|
||||
|
||||
Default: ``False``
|
||||
|
||||
A boolean that specifies whether to use the X-Forwarded-Host header in
|
||||
preference to the Host header. This should only be enabled if a proxy
|
||||
which sets this header is in use.
|
||||
|
||||
.. setting:: YEAR_MONTH_FORMAT
|
||||
|
||||
YEAR_MONTH_FORMAT
|
||||
|
@ -2,12 +2,14 @@ import time
|
||||
from datetime import datetime, timedelta
|
||||
from StringIO import StringIO
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.handlers.modpython import ModPythonRequest
|
||||
from django.core.handlers.wsgi import WSGIRequest, LimitedStream
|
||||
from django.http import HttpRequest, HttpResponse, parse_cookie
|
||||
from django.utils import unittest
|
||||
from django.utils.http import cookie_date
|
||||
|
||||
|
||||
class RequestsTests(unittest.TestCase):
|
||||
def test_httprequest(self):
|
||||
request = HttpRequest()
|
||||
@ -58,6 +60,94 @@ class RequestsTests(unittest.TestCase):
|
||||
self.assertEqual(request.build_absolute_uri(location="/path/with:colons"),
|
||||
'http://www.example.com/path/with:colons')
|
||||
|
||||
def test_http_get_host(self):
|
||||
old_USE_X_FORWARDED_HOST = settings.USE_X_FORWARDED_HOST
|
||||
try:
|
||||
settings.USE_X_FORWARDED_HOST = False
|
||||
|
||||
# Check if X_FORWARDED_HOST is provided.
|
||||
request = HttpRequest()
|
||||
request.META = {
|
||||
u'HTTP_X_FORWARDED_HOST': u'forward.com',
|
||||
u'HTTP_HOST': u'example.com',
|
||||
u'SERVER_NAME': u'internal.com',
|
||||
u'SERVER_PORT': 80,
|
||||
}
|
||||
# X_FORWARDED_HOST is ignored.
|
||||
self.assertEqual(request.get_host(), 'example.com')
|
||||
|
||||
# Check if X_FORWARDED_HOST isn't provided.
|
||||
request = HttpRequest()
|
||||
request.META = {
|
||||
u'HTTP_HOST': u'example.com',
|
||||
u'SERVER_NAME': u'internal.com',
|
||||
u'SERVER_PORT': 80,
|
||||
}
|
||||
self.assertEqual(request.get_host(), 'example.com')
|
||||
|
||||
# Check if HTTP_HOST isn't provided.
|
||||
request = HttpRequest()
|
||||
request.META = {
|
||||
u'SERVER_NAME': u'internal.com',
|
||||
u'SERVER_PORT': 80,
|
||||
}
|
||||
self.assertEqual(request.get_host(), 'internal.com')
|
||||
|
||||
# Check if HTTP_HOST isn't provided, and we're on a nonstandard port
|
||||
request = HttpRequest()
|
||||
request.META = {
|
||||
u'SERVER_NAME': u'internal.com',
|
||||
u'SERVER_PORT': 8042,
|
||||
}
|
||||
self.assertEqual(request.get_host(), 'internal.com:8042')
|
||||
|
||||
finally:
|
||||
settings.USE_X_FORWARDED_HOST = old_USE_X_FORWARDED_HOST
|
||||
|
||||
def test_http_get_host_with_x_forwarded_host(self):
|
||||
old_USE_X_FORWARDED_HOST = settings.USE_X_FORWARDED_HOST
|
||||
try:
|
||||
settings.USE_X_FORWARDED_HOST = True
|
||||
|
||||
# Check if X_FORWARDED_HOST is provided.
|
||||
request = HttpRequest()
|
||||
request.META = {
|
||||
u'HTTP_X_FORWARDED_HOST': u'forward.com',
|
||||
u'HTTP_HOST': u'example.com',
|
||||
u'SERVER_NAME': u'internal.com',
|
||||
u'SERVER_PORT': 80,
|
||||
}
|
||||
# X_FORWARDED_HOST is obeyed.
|
||||
self.assertEqual(request.get_host(), 'forward.com')
|
||||
|
||||
# Check if X_FORWARDED_HOST isn't provided.
|
||||
request = HttpRequest()
|
||||
request.META = {
|
||||
u'HTTP_HOST': u'example.com',
|
||||
u'SERVER_NAME': u'internal.com',
|
||||
u'SERVER_PORT': 80,
|
||||
}
|
||||
self.assertEqual(request.get_host(), 'example.com')
|
||||
|
||||
# Check if HTTP_HOST isn't provided.
|
||||
request = HttpRequest()
|
||||
request.META = {
|
||||
u'SERVER_NAME': u'internal.com',
|
||||
u'SERVER_PORT': 80,
|
||||
}
|
||||
self.assertEqual(request.get_host(), 'internal.com')
|
||||
|
||||
# Check if HTTP_HOST isn't provided, and we're on a nonstandard port
|
||||
request = HttpRequest()
|
||||
request.META = {
|
||||
u'SERVER_NAME': u'internal.com',
|
||||
u'SERVER_PORT': 8042,
|
||||
}
|
||||
self.assertEqual(request.get_host(), 'internal.com:8042')
|
||||
|
||||
finally:
|
||||
settings.USE_X_FORWARDED_HOST = old_USE_X_FORWARDED_HOST
|
||||
|
||||
def test_near_expiration(self):
|
||||
"Cookie will expire when an near expiration time is provided"
|
||||
response = HttpResponse()
|
||||
|
Loading…
x
Reference in New Issue
Block a user