最直接有效的方式是在Nginx层做Host头白名单校验,通过default_server拦截未匹配域名的请求并返回403,覆盖IP访问、伪造域名、含下划线域名、空或缺失Host头等非法请求。

最直接有效的方式,是在 Nginx 层做 Host 头白名单校验,所有不匹配预设域名的请求,在到达后端前就返回 403 或直接断连。这不需要改代码,也不依赖后端逻辑,是防御 Host 头攻击的第一道也是最关键的防线。
用 default_server 拦截未匹配的 Host 请求
这是最常用、最稳妥的方案。Nginx 会把所有 Host 头不匹配任何 server_name 的请求,交给标记为 default_server 的块处理。只要把它配成“拒绝专用 server”,就能覆盖绝大多数非法请求,包括:
- 直接用 IP 访问(如 http://192.168.1.100)
- 伪造的域名(如 Host: evil.com)
- 含下划线的域名(如 Host: admin_internal.example.com,Nginx 默认不认下划线)
- 空 Host 头或缺失 Host 头的请求
配置示例(放在独立 conf 文件中,建议以 00-block-host.conf 命名,确保最先加载):
server {
listen 80 default_server;
server_name _;
return 403;
}
<p>server {
listen 443 ssl default_server;
server<em>name </em>;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
return 403;
}注意:HTTPS 的 default_server 必须配有效证书,否则 TLS 握手阶段就会失败,用户看到的是证书错误,而不是 403。
主业务 server 显式声明合法域名
在 default_server 之后,再定义你真正提供服务的 server 块,并严格列出所有允许的域名:
server {
listen 80;
listen 443 ssl;
server_name example.com www.example.com api.example.com;
<pre class='brush:php;toolbar:false;'>ssl_certificate /path/to/main.pem;
ssl_certificate_key /path/to/main.key;
location / {
proxy_pass http://backend;
# 其他转发配置...
}}
关键点:
- 不要写 server_name * 或留空 —— 这会让 Nginx 接受任意 Host
- 多个域名用空格分隔,不支持通配符(如 *.example.com 需用正则或 map 模块)
- 如果需要泛域名支持,建议配合 map 模块做更灵活的白名单判断
用 set + if 实现精细控制(适合单域名场景)
当业务只跑一个主域名,且希望逻辑清晰、避免 default_server 语义模糊时,可用标志位方式校验:
server {
listen 80;
listen 443 ssl;
server_name _; # 此处 server_name 只是占位,实际靠 if 判断
<pre class='brush:php;toolbar:false;'>ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
set $host_ok 0;
if ($host = "example.com") { set $host_ok 1; }
if ($host = "www.example.com") { set $host_ok 1; }
if ($host_ok = 0) { return 403; }
location / {
proxy_pass http://backend;
}}
优点是判断逻辑集中、可读性强;缺点是 if 在 location 外使用有局限,不适用于复杂多条件场景。生产环境推荐优先用 default_server 方式。
补充:拦截纯 IP 访问与 hosts 劫持
本地 hosts 文件篡改、或通过 IP 直连,常被用于绕过 WAF 或探测隐藏服务。Nginx 默认会把这类请求归入第一个或 default_server 块。因此上面的 default_server 配置已天然覆盖该风险。若想进一步加固,还可加一条:
if ($host ~ "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$") {
return 403;
}这条规则能识别 IPv4 地址格式的 Host 头并拦截,对防止内网扫描和恶意解析有帮助。IPv6 可用更长正则匹配,按需启用。


















