Trusted Host Middleware
A lightweight production-ready trusted host middleware for the sillo framework.
Trusted Host Middleware
Section titled “Trusted Host Middleware”A lightweight, production‑ready trusted host middleware for the sillo ASGI framework.
It automatically validates the Host header of incoming requests against a configurable list of allowed hosts to prevent Host header attacks and ensure requests only come from trusted domains.
Installation
Section titled “Installation”uv add sillo-contribQuick Start
Section titled “Quick Start”from sillo import silloAppimport sillo_contrib.trusted as trusted
app = silloApp()
# Add the Trusted Host middlewareapp.use( trusted.TrustedHost( allowed_hosts=[ "example.com", "api.example.com", "*.example.com", # Wildcard support "127.0.0.1", "localhost" ], allowed_ports=[80, 443, 8000], # Optional: restrict ports www_redirect=True # Redirect www.example.com to example.com ))
@app.get("/")async def home(request, response): return {"message": "Hello from trusted host!"}Configuration
Section titled “Configuration”Required Parameters
Section titled “Required Parameters”allowed_hosts: List[str]
List of allowed hostnames, IP addresses, or patterns. Supports wildcards (e.g.,"*.example.com")
Optional Parameters
Section titled “Optional Parameters”-
allowed_ports: Optional[List[int]] = None
List of allowed ports. If specified, only requests to these ports will be allowed. IfNone, all ports are allowed. -
www_redirect: bool = True
IfTrue, automatically allows requests fromwww.domain.comifdomain.comis in the allowed hosts list.
Host Patterns
Section titled “Host Patterns”The middleware supports several types of host patterns:
Exact Hosts
Section titled “Exact Hosts”allowed_hosts = ["example.com", "api.example.com"]IP Addresses
Section titled “IP Addresses”allowed_hosts = ["127.0.0.1", "192.168.1.100"]Wildcard Patterns
Section titled “Wildcard Patterns”allowed_hosts = ["*.example.com", "*.api.example.com"]Port Restrictions
Section titled “Port Restrictions”allowed_hosts = ["example.com"]allowed_ports = [80, 443] # Only HTTP and HTTPSHow It Works
Section titled “How It Works”-
Host Extraction: Extracts the host from request headers with proper precedence:
X-Forwarded-Host(for proxies/load balancers)X-Host(some proxies)Hostheader (standard)
-
Validation: Checks the extracted host against the allowed patterns:
- Normalizes hosts to lowercase
- Validates against exact matches and wildcard patterns
- Checks port restrictions if specified
-
Security: Rejects requests with untrusted hosts using
400 Bad Request -
WWW Handling: Optionally allows
www.domain.comifdomain.comis trusted
Security Features
Section titled “Security Features”- Host Header Attack Prevention: Blocks requests with malicious Host headers
- Proxy Support: Properly handles forwarded headers from reverse proxies
- Port Security: Optional port restrictions for additional security
- Case Insensitive: All host validation is case insensitive
- Wildcard Support: Flexible pattern matching for subdomains
Examples
Section titled “Examples”Basic Setup
Section titled “Basic Setup”trusted.TrustedHost(allowed_hosts=["example.com", "api.example.com"])Development Environment
Section titled “Development Environment”trusted.TrustedHost( allowed_hosts=["localhost", "127.0.0.1", "*.local"], allowed_ports=[3000, 8000, 8080])Production with CDN
Section titled “Production with CDN”trusted.TrustedHost( allowed_hosts=[ "example.com", "www.example.com", "*.example.com", "cdn.example.com" ], allowed_ports=[80, 443])Multiple Domains
Section titled “Multiple Domains”trusted.TrustedHost( allowed_hosts=[ "example.com", "myapp.com", "staging.example.com", "api.myapp.com" ])Error Handling
Section titled “Error Handling”When a request comes from an untrusted host, the middleware raises:
BadRequestexception with a descriptive message- HTTP 400 status code is returned to the client
# Example error response{ "error": "Untrusted host", "detail": "Host 'malicious.com' is not allowed"}Advanced Usage
Section titled “Advanced Usage”Custom Error Handling
Section titled “Custom Error Handling”from sillo import silloAppfrom sillo.exceptions import BadRequest
app = silloApp()
@app.add_exception_handler(BadRequest)async def handle_bad_request(request, response, exc): if "Untrusted host" in str(exc): # Custom response for untrusted hosts return { "error": "Access Denied", "message": "This domain is not authorized to access this service" }, 403
# Default handling for other BadRequest exceptions return {"error": str(exc)}, 400Dynamic Host Configuration
Section titled “Dynamic Host Configuration”import osfrom sillo_contrib.trusted import TrustedHost
# Load allowed hosts from environmentallowed_hosts = os.getenv("ALLOWED_HOSTS", "localhost").split(",")
app.use( TrustedHost( allowed_hosts=allowed_hosts, allowed_ports=[80, 443] if os.getenv("PRODUCTION") else None ))Health Check Bypass
Section titled “Health Check Bypass”from sillo_contrib.trusted import TrustedHostMiddleware
class HealthCheckTrustedHost(TrustedHostMiddleware): def __init__(self, health_check_path="/health", **kwargs): super().__init__(**kwargs) self.health_check_path = health_check_path
async def __call__(self, request, response, call_next): # Skip host validation for health checks if request.url.path == self.health_check_path: return await call_next()
return await super().__call__(request, response, call_next)
app.use( HealthCheckTrustedHost( allowed_hosts=["example.com"], health_check_path="/health" ))Best Practices
Section titled “Best Practices”- Always specify allowed_hosts: Never leave this empty or use wildcards like
["*"]in production - Use HTTPS ports: In production, typically restrict to ports 80 and 443
- Consider your deployment: Behind load balancers? Use
X-Forwarded-Hostsupport - Environment specific: Use different configurations for development vs production
- Subdomain handling: Use wildcards for flexible subdomain support
- IP restrictions: Include your server’s IP addresses in allowed hosts for health checks
Common Scenarios
Section titled “Common Scenarios”Behind Nginx Proxy
Section titled “Behind Nginx Proxy”# Nginx sets X-Forwarded-Host headertrusted.TrustedHost( allowed_hosts=["example.com", "www.example.com"], allowed_ports=[80, 443])Kubernetes Ingress
Section titled “Kubernetes Ingress”# Multiple ingress domainstrusted.TrustedHost( allowed_hosts=[ "api.example.com", "*.staging.example.com", "internal.cluster.local" ])Microservices
Section titled “Microservices”# Allow internal service communicationtrusted.TrustedHost( allowed_hosts=[ "service-a.internal", "service-b.internal", "*.example.com" # External traffic ])Troubleshooting
Section titled “Troubleshooting”Common Issues
Section titled “Common Issues”Host header not found
- Check if your proxy is forwarding the Host header correctly
- Verify X-Forwarded-Host is set if behind a proxy
Wildcard not matching
- Ensure wildcard patterns use
*not regex syntax *.example.commatchesapi.example.combut notexample.com
Port restrictions too strict
- Include all ports your application runs on
- Consider load balancer port forwarding
Built with ❤️ by the @sillohq community.