mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #20038 -- Better error message for host validation.
This commit is contained in:
		
				
					committed by
					
						 Carl Meyer
						Carl Meyer
					
				
			
			
				
	
			
			
			
						parent
						
							c8deaa9e7b
						
					
				
				
					commit
					c250f9c99b
				
			| @@ -4,7 +4,6 @@ import copy | ||||
| import os | ||||
| import re | ||||
| import sys | ||||
| import warnings | ||||
| from io import BytesIO | ||||
| from pprint import pformat | ||||
| try: | ||||
| @@ -66,11 +65,14 @@ class HttpRequest(object): | ||||
|                 host = '%s:%s' % (host, server_port) | ||||
|  | ||||
|         allowed_hosts = ['*'] if settings.DEBUG else settings.ALLOWED_HOSTS | ||||
|         if validate_host(host, allowed_hosts): | ||||
|         domain, port = split_domain_port(host) | ||||
|         if domain and validate_host(domain, allowed_hosts): | ||||
|             return host | ||||
|         else: | ||||
|             raise SuspiciousOperation( | ||||
|                 "Invalid HTTP_HOST header (you may need to set ALLOWED_HOSTS): %s" % host) | ||||
|             msg = "Invalid HTTP_HOST header: %r." % host | ||||
|             if domain: | ||||
|                 msg += "You may need to add %r to ALLOWED_HOSTS." % domain | ||||
|             raise SuspiciousOperation(msg) | ||||
|  | ||||
|     def get_full_path(self): | ||||
|         # RFC 3986 requires query string arguments to be in the ASCII range. | ||||
| @@ -454,9 +456,30 @@ def bytes_to_text(s, encoding): | ||||
|         return s | ||||
|  | ||||
|  | ||||
| def split_domain_port(host): | ||||
|     """ | ||||
|     Return a (domain, port) tuple from a given host. | ||||
|  | ||||
|     Returned domain is lower-cased. If the host is invalid, the domain will be | ||||
|     empty. | ||||
|     """ | ||||
|     host = host.lower() | ||||
|  | ||||
|     if not host_validation_re.match(host): | ||||
|         return '', '' | ||||
|  | ||||
|     if host[-1] == ']': | ||||
|         # It's an IPv6 address without a port. | ||||
|         return host, '' | ||||
|     bits = host.rsplit(':', 1) | ||||
|     if len(bits) == 2: | ||||
|         return tuple(bits) | ||||
|     return bits[0], '' | ||||
|  | ||||
|  | ||||
| def validate_host(host, allowed_hosts): | ||||
|     """ | ||||
|     Validate the given host header value for this site. | ||||
|     Validate the given host for this site. | ||||
|  | ||||
|     Check that the host looks valid and matches a host or host pattern in the | ||||
|     given list of ``allowed_hosts``. Any pattern beginning with a period | ||||
| @@ -464,31 +487,20 @@ def validate_host(host, allowed_hosts): | ||||
|     ``example.com`` and any subdomain), ``*`` matches anything, and anything | ||||
|     else must match exactly. | ||||
|  | ||||
|     Note: This function assumes that the given host is lower-cased and has | ||||
|     already had the port, if any, stripped off. | ||||
|  | ||||
|     Return ``True`` for a valid host, ``False`` otherwise. | ||||
|  | ||||
|     """ | ||||
|     # All validation is case-insensitive | ||||
|     host = host.lower() | ||||
|  | ||||
|     # Basic sanity check | ||||
|     if not host_validation_re.match(host): | ||||
|         return False | ||||
|  | ||||
|     # Validate only the domain part. | ||||
|     if host[-1] == ']': | ||||
|         # It's an IPv6 address without a port. | ||||
|         domain = host | ||||
|     else: | ||||
|         domain = host.rsplit(':', 1)[0] | ||||
|  | ||||
|     for pattern in allowed_hosts: | ||||
|         pattern = pattern.lower() | ||||
|         match = ( | ||||
|             pattern == '*' or | ||||
|             pattern.startswith('.') and ( | ||||
|                 domain.endswith(pattern) or domain == pattern[1:] | ||||
|                 host.endswith(pattern) or host == pattern[1:] | ||||
|                 ) or | ||||
|             pattern == domain | ||||
|             pattern == host | ||||
|             ) | ||||
|         if match: | ||||
|             return True | ||||
|   | ||||
		Reference in New Issue
	
	Block a user