最有效的host头注入防御手段是用proxy_set_header host主动控制转发值。禁用proxy_set_header host $http_host和$host等透传写法,推荐使用$proxy_host、固定域名或清空host头,并配合x-real-ip等头部加固及host白名单拦截。

直接用 proxy_set_header Host 控制转发给后端的 Host 值,是最有效、最简单的 Host 头注入防御手段。核心就一条:别让客户端随便塞什么 Host,你就转发什么;而是由 Nginx 主动决定该发什么。
必须禁用透传写法
以下配置是高危行为,会直接暴露后端:
-
proxy_set_header Host $http_host;—— 完全信任客户端传来的 Host,含端口、大小写,攻击者可任意伪造 -
proxy_set_header Host $host;—— 虽比$http_host稍安全(自动标准化),但仍来自用户输入,不可信
只要用了这两行中的任意一个,攻击者发 curl -H "Host: evil.com" https://yoursite.com,后端就可能收到 Host: evil.com,进而触发重定向跳转、日志写入异常路径、租户路由错乱等风险。
推荐三种安全写法
选一种,按实际场景落地:
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
-
用
$proxy_host(最推荐):它取自proxy_pass指令里写的后端地址,比如proxy_pass http://backend:8080;,那$proxy_host就是backend:8080。不依赖业务域名,解耦清晰,也不怕后端改名 -
固定后端域名:适用于单应用、后端只认一个名字的场景,例如
proxy_set_header Host api.internal;。简单明确,便于审计 -
清空 Host 头(谨慎):某些后端根本不用 Host 头,可写
proxy_set_header Host "";。但务必确认后端兼容,否则可能返回 400 错误
配合其他头部一起加固
只修 Host 不够,攻击者还可能通过其他头搞事:
-
proxy_set_header X-Real-IP $remote_addr;—— 保证后端拿到真实客户端 IP,不被X-Forwarded-For伪造 -
proxy_set_header X-Forwarded-For $remote_addr;—— 不拼接原始值,避免链式污染 -
proxy_set_header X-Forwarded-Proto $scheme;—— 明确告诉后端是 http 还是 https,防止混合内容或跳转错误 -
proxy_hide_header Server;和proxy_hide_header X-Powered-By;—— 隐藏技术栈信息,减少攻击面
加一层 Host 白名单拦截
在请求进入代理逻辑前,先筛掉非法 Host:
- 所有
server块必须显式声明合法域名:server_name example.com www.example.com; - 额外定义一个
default_server,监听相同端口但不设server_name,里面只写return 444;或return 403; - 这样,
Host: 127.0.0.1、Host: attacker.net这类请求连代理逻辑都进不去,直接断连或拒绝
部署后用 curl -H "Host: fake.com" -v https://your-domain.com 验证,检查后端 access log 或响应头里的 Host 字段,确认它已变成你设定的值,而不是 fake.com。










