ALLOWED_HOSTS是否使用get_host()?Django主机验证机制咨询
关于Django ALLOWED_HOSTS验证逻辑的解惑
这个问题我之前做安全核查的时候也纠结过,刚好给你理清楚核心逻辑:
首先明确结论:Django的ALLOWED_HOSTS安全验证确实只在调用request.get_host()时才会生效,如果直接从request.META里读取Host相关字段(比如HTTP_HOST),完全会绕过这个安全防护。
为什么会这样?
Django把ALLOWED_HOSTS的验证逻辑完全封装在了get_host()方法里,这个方法做了两件关键的事:
- 先从
request.META中提取主机信息,还处理了HTTP_HOST不存在时用SERVER_NAME/SERVER_PORT兜底的逻辑 - 提取完成后,立刻用
ALLOWED_HOSTS的规则验证主机名,如果不匹配直接抛出SuspiciousOperation异常——这就是防护恶意Host头的核心步骤
而如果你直接读取request.META['HTTP_HOST'],相当于跳过了第二步的验证,哪怕请求的Host不在白名单里,你也能拿到原始值,这就给缓存投毒、域名欺骗之类的攻击留了口子。
关于你想写中间件的思路
如果你的需求是在请求链路里提前验证主机,或者加一套自定义的主机白名单,那通过get_host()获取主机再做对比的思路是完全可行的。
不过要提一句:Django其实已经内置了触发这个验证的中间件——django.middleware.common.CommonMiddleware,它在处理请求时会自动调用get_host(),从而触发ALLOWED_HOSTS的验证。如果你需要额外的自定义验证逻辑,可以写自己的中间件,在合适的时机(比如在CommonMiddleware之后,确保先通过内置验证)调用request.get_host(),再做额外检查。
举个简单的自定义中间件例子:
from django.core.exceptions import SuspiciousOperation class CustomHostCheckMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): # 先调用get_host()触发Django内置的ALLOWED_HOSTS验证 validated_host = request.get_host() # 自定义额外的主机白名单检查 my_allowed_hosts = ["app.example.com", "admin.example.com"] if validated_host not in my_allowed_hosts: raise SuspiciousOperation("该主机无权访问此服务") response = self.get_response(request) return response
最后再划个重点
- 永远用
request.get_host()获取主机名,不要直接读request.META里的字段 ALLOWED_HOSTS的安全防护完全依赖get_host()的调用,跳过这个方法就等于放弃防护- 自定义主机验证时,基于
get_host()来做是安全的,因为它已经帮你完成了基础的白名单校验
内容的提问来源于stack exchange,提问作者Jason Howard
相关产品推荐
相关产品推荐

