Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Isolated host validation tests in own test case

  • Loading branch information...
commit 73f86f44417f883ba3aca1ba947fdad00206a615 1 parent f2cb94f
@claudep claudep authored
Showing with 202 additions and 215 deletions.
  1. +202 −215 tests/requests/tests.py
View
417 tests/requests/tests.py
@@ -3,6 +3,7 @@
from datetime import datetime, timedelta
from io import BytesIO
+from itertools import chain
import time
from unittest import skipIf
import warnings
@@ -122,221 +123,6 @@ def test_httprequest_location(self):
self.assertEqual(request.build_absolute_uri(location="/path/with:colons"),
'http://www.example.com/path/with:colons')
- @override_settings(
- USE_X_FORWARDED_HOST=False,
- ALLOWED_HOSTS=[
- 'forward.com', 'example.com', 'internal.com', '12.34.56.78',
- '[2001:19f0:feee::dead:beef:cafe]', 'xn--4ca9at.com',
- '.multitenant.com', 'INSENSITIVE.com',
- ])
- def test_http_get_host(self):
- # Check if X_FORWARDED_HOST is provided.
- request = HttpRequest()
- request.META = {
- 'HTTP_X_FORWARDED_HOST': 'forward.com',
- 'HTTP_HOST': 'example.com',
- 'SERVER_NAME': 'internal.com',
- '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 = {
- 'HTTP_HOST': 'example.com',
- 'SERVER_NAME': 'internal.com',
- 'SERVER_PORT': 80,
- }
- self.assertEqual(request.get_host(), 'example.com')
-
- # Check if HTTP_HOST isn't provided.
- request = HttpRequest()
- request.META = {
- 'SERVER_NAME': 'internal.com',
- '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 = {
- 'SERVER_NAME': 'internal.com',
- 'SERVER_PORT': 8042,
- }
- self.assertEqual(request.get_host(), 'internal.com:8042')
-
- # Poisoned host headers are rejected as suspicious
- legit_hosts = [
- 'example.com',
- 'example.com:80',
- '12.34.56.78',
- '12.34.56.78:443',
- '[2001:19f0:feee::dead:beef:cafe]',
- '[2001:19f0:feee::dead:beef:cafe]:8080',
- 'xn--4ca9at.com', # Punnycode for öäü.com
- 'anything.multitenant.com',
- 'multitenant.com',
- 'insensitive.com',
- ]
-
- poisoned_hosts = [
- 'example.com@evil.tld',
- 'example.com:dr.frankenstein@evil.tld',
- 'example.com:dr.frankenstein@evil.tld:80',
- 'example.com:80/badpath',
- 'example.com: recovermypassword.com',
- 'other.com', # not in ALLOWED_HOSTS
- ]
-
- for host in legit_hosts:
- request = HttpRequest()
- request.META = {
- 'HTTP_HOST': host,
- }
- request.get_host()
-
- for host in poisoned_hosts:
- with self.assertRaises(SuspiciousOperation):
- request = HttpRequest()
- request.META = {
- 'HTTP_HOST': host,
- }
- request.get_host()
-
- @override_settings(USE_X_FORWARDED_HOST=True, ALLOWED_HOSTS=['*'])
- def test_http_get_host_with_x_forwarded_host(self):
- # Check if X_FORWARDED_HOST is provided.
- request = HttpRequest()
- request.META = {
- 'HTTP_X_FORWARDED_HOST': 'forward.com',
- 'HTTP_HOST': 'example.com',
- 'SERVER_NAME': 'internal.com',
- '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 = {
- 'HTTP_HOST': 'example.com',
- 'SERVER_NAME': 'internal.com',
- 'SERVER_PORT': 80,
- }
- self.assertEqual(request.get_host(), 'example.com')
-
- # Check if HTTP_HOST isn't provided.
- request = HttpRequest()
- request.META = {
- 'SERVER_NAME': 'internal.com',
- '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 = {
- 'SERVER_NAME': 'internal.com',
- 'SERVER_PORT': 8042,
- }
- self.assertEqual(request.get_host(), 'internal.com:8042')
-
- # Poisoned host headers are rejected as suspicious
- legit_hosts = [
- 'example.com',
- 'example.com:80',
- '12.34.56.78',
- '12.34.56.78:443',
- '[2001:19f0:feee::dead:beef:cafe]',
- '[2001:19f0:feee::dead:beef:cafe]:8080',
- 'xn--4ca9at.com', # Punnycode for öäü.com
- ]
-
- poisoned_hosts = [
- 'example.com@evil.tld',
- 'example.com:dr.frankenstein@evil.tld',
- 'example.com:dr.frankenstein@evil.tld:80',
- 'example.com:80/badpath',
- 'example.com: recovermypassword.com',
- ]
-
- for host in legit_hosts:
- request = HttpRequest()
- request.META = {
- 'HTTP_HOST': host,
- }
- request.get_host()
-
- for host in poisoned_hosts:
- with self.assertRaises(SuspiciousOperation):
- request = HttpRequest()
- request.META = {
- 'HTTP_HOST': host,
- }
- request.get_host()
-
-
- @override_settings(DEBUG=True, ALLOWED_HOSTS=[])
- def test_host_validation_disabled_in_debug_mode(self):
- """If ALLOWED_HOSTS is empty and DEBUG is True, all hosts pass."""
- request = HttpRequest()
- request.META = {
- 'HTTP_HOST': 'example.com',
- }
- self.assertEqual(request.get_host(), 'example.com')
-
-
- @override_settings(ALLOWED_HOSTS=[])
- def test_get_host_suggestion_of_allowed_host(self):
- """get_host() makes helpful suggestions if a valid-looking host is not in ALLOWED_HOSTS."""
- msg_invalid_host = "Invalid HTTP_HOST header: %r."
- msg_suggestion = msg_invalid_host + "You may need to add %r to ALLOWED_HOSTS."
-
- for host in [ # Valid-looking hosts
- 'example.com',
- '12.34.56.78',
- '[2001:19f0:feee::dead:beef:cafe]',
- 'xn--4ca9at.com', # Punnycode for öäü.com
- ]:
- request = HttpRequest()
- request.META = {'HTTP_HOST': host}
- self.assertRaisesMessage(
- SuspiciousOperation,
- msg_suggestion % (host, host),
- request.get_host
- )
-
- for domain, port in [ # Valid-looking hosts with a port number
- ('example.com', 80),
- ('12.34.56.78', 443),
- ('[2001:19f0:feee::dead:beef:cafe]', 8080),
- ]:
- host = '%s:%s' % (domain, port)
- request = HttpRequest()
- request.META = {'HTTP_HOST': host}
- self.assertRaisesMessage(
- SuspiciousOperation,
- msg_suggestion % (host, domain),
- request.get_host
- )
-
- for host in [ # Invalid hosts
- 'example.com@evil.tld',
- 'example.com:dr.frankenstein@evil.tld',
- 'example.com:dr.frankenstein@evil.tld:80',
- 'example.com:80/badpath',
- 'example.com: recovermypassword.com',
- ]:
- request = HttpRequest()
- request.META = {'HTTP_HOST': host}
- self.assertRaisesMessage(
- SuspiciousOperation,
- msg_invalid_host % host,
- request.get_host
- )
-
-
def test_near_expiration(self):
"Cookie will expire when an near expiration time is provided"
response = HttpResponse()
@@ -678,6 +464,207 @@ def read(self, len=0):
request.FILES
+class HostValidationTests(SimpleTestCase):
+ poisoned_hosts = [
+ 'example.com@evil.tld',
+ 'example.com:dr.frankenstein@evil.tld',
+ 'example.com:dr.frankenstein@evil.tld:80',
+ 'example.com:80/badpath',
+ 'example.com: recovermypassword.com',
+ ]
+
+ @override_settings(
+ USE_X_FORWARDED_HOST=False,
+ ALLOWED_HOSTS=[
+ 'forward.com', 'example.com', 'internal.com', '12.34.56.78',
+ '[2001:19f0:feee::dead:beef:cafe]', 'xn--4ca9at.com',
+ '.multitenant.com', 'INSENSITIVE.com',
+ ])
+ def test_http_get_host(self):
+ # Check if X_FORWARDED_HOST is provided.
+ request = HttpRequest()
+ request.META = {
+ 'HTTP_X_FORWARDED_HOST': 'forward.com',
+ 'HTTP_HOST': 'example.com',
+ 'SERVER_NAME': 'internal.com',
+ '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 = {
+ 'HTTP_HOST': 'example.com',
+ 'SERVER_NAME': 'internal.com',
+ 'SERVER_PORT': 80,
+ }
+ self.assertEqual(request.get_host(), 'example.com')
+
+ # Check if HTTP_HOST isn't provided.
+ request = HttpRequest()
+ request.META = {
+ 'SERVER_NAME': 'internal.com',
+ '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 = {
+ 'SERVER_NAME': 'internal.com',
+ 'SERVER_PORT': 8042,
+ }
+ self.assertEqual(request.get_host(), 'internal.com:8042')
+
+ legit_hosts = [
+ 'example.com',
+ 'example.com:80',
+ '12.34.56.78',
+ '12.34.56.78:443',
+ '[2001:19f0:feee::dead:beef:cafe]',
+ '[2001:19f0:feee::dead:beef:cafe]:8080',
+ 'xn--4ca9at.com', # Punnycode for öäü.com
+ 'anything.multitenant.com',
+ 'multitenant.com',
+ 'insensitive.com',
+ ]
+
+ for host in legit_hosts:
+ request = HttpRequest()
+ request.META = {
+ 'HTTP_HOST': host,
+ }
+ request.get_host()
+
+ # Poisoned host headers are rejected as suspicious
+ for host in chain(self.poisoned_hosts, ['other.com']):
+ with self.assertRaises(SuspiciousOperation):
+ request = HttpRequest()
+ request.META = {
+ 'HTTP_HOST': host,
+ }
+ request.get_host()
+
+ @override_settings(USE_X_FORWARDED_HOST=True, ALLOWED_HOSTS=['*'])
+ def test_http_get_host_with_x_forwarded_host(self):
+ # Check if X_FORWARDED_HOST is provided.
+ request = HttpRequest()
+ request.META = {
+ 'HTTP_X_FORWARDED_HOST': 'forward.com',
+ 'HTTP_HOST': 'example.com',
+ 'SERVER_NAME': 'internal.com',
+ '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 = {
+ 'HTTP_HOST': 'example.com',
+ 'SERVER_NAME': 'internal.com',
+ 'SERVER_PORT': 80,
+ }
+ self.assertEqual(request.get_host(), 'example.com')
+
+ # Check if HTTP_HOST isn't provided.
+ request = HttpRequest()
+ request.META = {
+ 'SERVER_NAME': 'internal.com',
+ '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 = {
+ 'SERVER_NAME': 'internal.com',
+ 'SERVER_PORT': 8042,
+ }
+ self.assertEqual(request.get_host(), 'internal.com:8042')
+
+ # Poisoned host headers are rejected as suspicious
+ legit_hosts = [
+ 'example.com',
+ 'example.com:80',
+ '12.34.56.78',
+ '12.34.56.78:443',
+ '[2001:19f0:feee::dead:beef:cafe]',
+ '[2001:19f0:feee::dead:beef:cafe]:8080',
+ 'xn--4ca9at.com', # Punnycode for öäü.com
+ ]
+
+ for host in legit_hosts:
+ request = HttpRequest()
+ request.META = {
+ 'HTTP_HOST': host,
+ }
+ request.get_host()
+
+ for host in self.poisoned_hosts:
+ with self.assertRaises(SuspiciousOperation):
+ request = HttpRequest()
+ request.META = {
+ 'HTTP_HOST': host,
+ }
+ request.get_host()
+
+
+ @override_settings(DEBUG=True, ALLOWED_HOSTS=[])
+ def test_host_validation_disabled_in_debug_mode(self):
+ """If ALLOWED_HOSTS is empty and DEBUG is True, all hosts pass."""
+ request = HttpRequest()
+ request.META = {
+ 'HTTP_HOST': 'example.com',
+ }
+ self.assertEqual(request.get_host(), 'example.com')
+
+
+ @override_settings(ALLOWED_HOSTS=[])
+ def test_get_host_suggestion_of_allowed_host(self):
+ """get_host() makes helpful suggestions if a valid-looking host is not in ALLOWED_HOSTS."""
+ msg_invalid_host = "Invalid HTTP_HOST header: %r."
+ msg_suggestion = msg_invalid_host + "You may need to add %r to ALLOWED_HOSTS."
+
+ for host in [ # Valid-looking hosts
+ 'example.com',
+ '12.34.56.78',
+ '[2001:19f0:feee::dead:beef:cafe]',
+ 'xn--4ca9at.com', # Punnycode for öäü.com
+ ]:
+ request = HttpRequest()
+ request.META = {'HTTP_HOST': host}
+ self.assertRaisesMessage(
+ SuspiciousOperation,
+ msg_suggestion % (host, host),
+ request.get_host
+ )
+
+ for domain, port in [ # Valid-looking hosts with a port number
+ ('example.com', 80),
+ ('12.34.56.78', 443),
+ ('[2001:19f0:feee::dead:beef:cafe]', 8080),
+ ]:
+ host = '%s:%s' % (domain, port)
+ request = HttpRequest()
+ request.META = {'HTTP_HOST': host}
+ self.assertRaisesMessage(
+ SuspiciousOperation,
+ msg_suggestion % (host, domain),
+ request.get_host
+ )
+
+ for host in self.poisoned_hosts:
+ request = HttpRequest()
+ request.META = {'HTTP_HOST': host}
+ self.assertRaisesMessage(
+ SuspiciousOperation,
+ msg_invalid_host % host,
+ request.get_host
+ )
+
+
@skipIf(connection.vendor == 'sqlite'
and connection.settings_dict['TEST_NAME'] in (None, '', ':memory:'),
"Cannot establish two connections to an in-memory SQLite database.")
Please sign in to comment.
Something went wrong with that request. Please try again.