DisallowedHost

Исключение DisallowedHost выбрасывается при обработке входящего HTTP-запроса, если значение заголовка Host не соответствует ни одному из допустимых доменов в настройке ALLOWED_HOSTS. Это критически важная защита от уязвимостей, связанных с подделкой заголовка хоста, которые могут привести к инъекциям паролей, кеш-отравлению и другим атакам. Исключение наследуется от SuspiciousOperation и обрабатывается промежуточным слоем Django.

Синтаксис

pythonfrom django.core.exceptions import DisallowedHost

# Исключение создается автоматически при несовпадении Host
raise DisallowedHost("Invalid HTTP_HOST header")

Пример

Рассмотрим базовую настройку допустимых хостов в проекте:

python# settings.py
ALLOWED_HOSTS = ['example.com', 'www.example.com', '127.0.0.1']

Если Django получит запрос с заголовком Host, отличным от указанных, произойдет исключение:

python# Запрос с Host: malicious-site.com
# Django автоматически возбуждает DisallowedHost

from django.core.exceptions import DisallowedHost

try:
  # В реальности это происходит в обработчике запроса
  raise DisallowedHost("HTTP_HOST header: 'malicious-site.com'")
except DisallowedHost as e:
  print(f"Ошибка безопасности: {e}")

Результат выполнения кода:

python"Ошибка безопасности: HTTP_HOST header: 'malicious-site.com'"

Пример

Исключение также возникает при запросах без заголовка Host или с некорректным форматом. Обработаем ситуацию с помощью промежуточного слоя:

pythonfrom django.core.exceptions import DisallowedHost
from django.http import HttpRequest

def process_request(request: HttpRequest):
  try:
    # Имитация проверки Host в middleware
    allowed = ['myapp.com', 'api.myapp.com']
    host = request.get_host()
    if host not in allowed:
      raise DisallowedHost(f"Host '{host}' not allowed")
  except DisallowedHost as e:
    print(f"Заблокирован запрос: {e}")
    return None  # В реальности возвращается HTTP 400

# Проверяем с некорректным хостом
req = HttpRequest()
req.META['HTTP_HOST'] = 'fake-domain.net'
process_request(req)

Результат выполнения кода:

python"Заблокирован запрос: Host 'fake-domain.net' not allowed"

Пример

Для корректной обработки в продакшене список ALLOWED_HOSTS должен включать все домены, которые обслуживает приложение. Динамическое определение хоста демонстрирует гибкость настройки:

pythonimport os
from django.core.exceptions import DisallowedHost

# Динамическое определение разрешенных хостов
ALLOWED_HOSTS = os.getenv('DJANGO_ALLOWED_HOSTS', 'localhost,127.0.0.1').split(',')

def validate_host(host: str) -> bool:
  for allowed in ALLOWED_HOSTS:
    if host == allowed or (allowed.startswith('.') and host.endswith(allowed)):
      return True
  raise DisallowedHost(f"Host '{host}' is not in ALLOWED_HOSTS")

try:
  validate_host('sub.example.com')  # example.com в ALLOWED_HOSTS
except DisallowedHost as e:
  print(f"Исключение: {e}")

Результат выполнения кода:

python"Исключение: Host 'sub.example.com' is not in ALLOWED_HOSTS"

Смотрите также

  • исключение SuspiciousOperation,
    базовое исключение для подозрительных операций
  • исключение DisallowedRedirect,
    возникает при запрещенном перенаправлении
  • исключение BadRequest,
    сигнализирует о некорректном запросе
  • исключение ImproperlyConfigured,
    указывает на ошибки в конфигурации Django