[Django] DisallowedHost突然爆发?ALLOWED_HOSTS=‘*‘为什么没用+中间件根治方案(附代码)

发布时间:2026/9/27 16:14:18
[Django] DisallowedHost突然爆发?ALLOWED_HOSTS=‘*‘为什么没用+中间件根治方案(附代码) Django 生产环境 DisallowedHost 突然爆发ALLOWED_HOSTS[*] 为什么没用TL;DR你的 Django 项目突然开始报DisallowedHost日志里 Host 是一个奇怪的下划线_而你明明设了ALLOWED_HOSTS [*]。问题出在 Django 的 Host 校验分两步——先做 RFC 1034/1035 域名合法性校验通过才查 ALLOWED_HOSTS。_不是合法域名连第一关都过不去。根治方案一个 15 行的中间件在 CommonMiddleware 之前拦截。1. 事故现场某天早上含光博客的日志/邮件告警里出现了这样一个错误关键信息已标注DisallowedHostat/InvalidHTTP_HOSTheader:_.ThedomainnameprovidedisnotvalidaccordingtoRFC1034/1035.# ⬇ 三行关键证据HTTP_HOST_HTTP_USER_AGENTHello from Palo Alto Networks, find out more about our scans...HTTP_X_FORWARDED_FOR203.0.113.1ALLOWED_HOSTS[*,127.0.0.1,example.com]# ← 明明设了通配符第一反应ALLOWED_HOSTS [*]不是应该放行所有 Host 吗怎么还报 DisallowedHost2. 根因Django 的 Host 校验是两步不是一步翻 Django 源码django/http/request.pyget_host()方法的逻辑是defget_host(self):hostself._get_raw_host()# 从 HTTP_HOST / SERVER_NAME 取# 第一步RFC 1034/1035 域名合法性校验host,portsplit_domain_port(host)ifhostandnothost_validation_re.match(host):raiseDisallowedHost(fInvalid HTTP_HOST header:{host!r}.)# 第二步ALLOWED_HOSTS 白名单比对ifnotvalidate_host(host,settings.ALLOWED_HOSTS):raiseDisallowedHost(fInvalid HTTP_HOST header:{host!r}.)returnhost关键发现第一步的host_validation_re正则在对ALLOWED_HOSTS生效之前就已经跑了。_为什么通不过这个正则因为 RFC 1034/1035 规定域名只能包含字母、数字和连字符-_下划线不在合法字符集中。所以_直接在第一关被毙根本走不到第二步的通配符*。Host 值第一步RFC 校验第二步ALLOWED_HOSTS结果www.baidu.com✅✅200_.com❌含_不会走到DisallowedHost纯数字 IP1.2.3.4✅✅200单下划线_❌不会走到DisallowedHostexample.com✅✅200ALLOWED_HOSTS [*]保证的是第二步永远通过但救不了第一步的 RFC 合规性检查。3. 这些畸形 Host 从哪来互联网扫描器Shodan、Censys、Palo Alto Cortex Xpanse 等在持续探测公网资产。它们发请求时可能会设Host: 你的IP用 IP 而非域名设Host: _占位符/探测标记设Host: scriptalert(1)/scriptXSS 探测完全不发 Host 头某些 HTTP/1.0 客户端这些都不是攻击——只是常规资产扫描。但 Django 默认会为每个 DisallowedHost 记录 traceback 发邮件给 ADMINS日志和邮箱很快会被撑满。4. 解决方案对比方案拦截点副作用推荐度方案 ADjango 自定义中间件应用层Django无⭐⭐⭐⭐⭐方案 BNginx/Caddy 过滤反向代理层需 Web Server 配合⭐⭐⭐⭐方案 C修改 ALLOWED_HOSTS配置治标不治本见第 2 节⭐方案 D忽略日志无核弹级——真正的攻击 Host 注入也会被掩盖❌推荐方案 A原因是 1. 不依赖 Web Server含光博客的 Nginx 是 frp 穿透进来的直接配 Nginx 有坑 2. 15 行代码无外部依赖 3. 精确控制——只拦截畸形 Host正常请求零影响5. 实现BlockBadHostMiddleware在 Django 项目的middleware.py或任何 middleware 文件中添加importrefromdjango.httpimportHttpResponse# RFC 1034/1035 合法域名正则# 匹配example.com / sub.example.com / localhost / 纯 IPv4# 不匹配_ / _something / -bad.com_HOST_REre.compile(r^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?r(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$)classBlockBadHostMiddleware:在 CommonMiddleware 之前拦截无效 Host避免 DisallowedHost tracebackdef__init__(self,get_response):self.get_responseget_responsedef__call__(self,request):hostrequest.META.get(HTTP_HOST,)ifhostandnot_HOST_RE.match(host.split(:)[0]):returnHttpResponse(Bad Request,status400)returnself.get_response(request)然后在settings.py的MIDDLEWARE列表最前面插入MIDDLEWARE[yourapp.middleware.BlockBadHostMiddleware,# ← 必须第一位django.middleware.security.SecurityMiddleware,# ... 其他中间件]为什么必须第一位Django 中间件按列表顺序执行。CommonMiddleware包含get_host()调用如果在BlockBadHostMiddleware之前执行拦截器就没机会跑了。6. 验证# 畸形 Host → 400$curl-s-o/dev/null-w%{http_code}http://127.0.0.1:8770/-HHost: _400# 正常域名 → 200$curl-s-o/dev/null-w%{http_code}http://127.0.0.1:8770/-HHost: www.baidu.com200畸形 Host 被静默拦截为 400不再触发 traceback 和邮件告警。正常请求零影响。7. 延伸为什么 DNS 允许下划线但 HTTP Host 不允许这里有一个容易混淆的点DNS 层面SRV 记录_http._tcp.example.com和 DKIM/SPF 等确实使用下划线RFC 2181 明确说DNS 不对 label 内容做限制HTTP Host 头层面RFC 952 RFC 1123主机名规范禁止下划线。Django 的host_validation_re遵循的是主机名规范不是 DNS 规范所以_dmarc.example.com作为 DNS 记录是合法的但作为 HTTP Host 头传给 Django 就会被拒绝——除非你在前面放了这个中间件。8. 总结你看到的真实原因修法DisallowedHost: _扫描器发的畸形 Host自定义中间件返回 400 而不是抛异常ALLOWED_HOSTS[*]却没用*只管第二步管不了第一步 RFC 校验中间件插在 MIDDLEWARE 第一位日志/邮箱被撑满每个畸形请求都触发 traceback 邮件拦截后只返回 400无 traceback这个错误在生产环境非常常见——任何暴露在公网的 Django 项目都会被扫描器光顾。上述 15 行中间件可以永久解决这个问题。本文代码已在 Django 5.2 Gunicorn 生产环境中验证通过。如果你也有类似的排查经验欢迎在评论区交流。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询