Introduction
The Host header tells Django which domain was requested. Attackers can manipulate this header to poison caches, steal credentials, or bypass security controls. ALLOWED_HOSTS is your defense.
Key Concepts
Host Header: HTTP header indicating the domain the client is requesting.
Host Header Injection: Attack where malicious Host values trick the application.
ALLOWED_HOSTS: Django setting that whitelists valid Host header values.
Real World Context
Host header attacks can:
- Poison password reset links (send reset emails with attacker's domain)
- Bypass access controls based on domain
- Cache poisoning in CDNs
- SSRF (Server-Side Request Forgery) exploitation
Deep Dive
Configuring ALLOWED_HOSTS
python# settings.py # Production - explicit domains only ALLOWED_HOSTS = ['example.com', 'www.example.com'] # With subdomain wildcard ALLOWED_HOSTS = ['.example.com'] # Matches any subdomain # NEVER in production ALLOWED_HOSTS = ['*'] # Accepts ANY host - dangerous!
Environment-Based Configuration
pythonimport os ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',') # Development fallback if DEBUG: ALLOWED_HOSTS = ['localhost', '127.0.0.1', '[::1]']
Password Reset Attack Example
python# Vulnerable code def password_reset(request): token = generate_token(user) # Attacker sets Host: evil.com reset_url = f"http://{request.get_host()}/reset/{token}" send_email(user.email, reset_url) # Link points to evil.com!
python# Safe code def password_reset(request): token = generate_token(user) # Use explicit domain reset_url = f"https://example.com/reset/{token}" send_email(user.email, reset_url)
Common Pitfalls
- Using ALLOWED_HOSTS = ['*']: Disables protection entirely.
- Forgetting www variant: Users on www.example.com get 400 errors.
- Using request.get_host() in sensitive places: Can return attacker-controlled values.
Best Practices
- Explicit domains only: List exact domains, avoid wildcards.
- Use absolute URLs for sensitive links: Don't rely on Host header.
- Configure CSRF_TRUSTED_ORIGINS: Required for HTTPS cross-origin requests.
Summary
ALLOWED_HOSTS protects against Host header injection attacks. Always configure it explicitly in production, never use '*', and avoid using request.get_host() for security-sensitive URLs like password resets.