Nginx 版本号隐藏配置实战:防指纹信息泄露

适用场景

  • 网站尚未接入 WAF,响应头直接暴露 nginx/1.x.x 版本信息
  • 渗透测试报告中出现「Web 服务器版本泄露」中危项
  • 希望降低被自动化扫描器按版本精准匹配 CVE 命中的概率

前置条件

  • 已安装 Nginx(1.18 以上版本,本文以 1.24 为例)
  • 拥有 root 或 sudo 权限,可修改主配置文件
  • 掌握基本的 nginx -t 语法检查与 reload 操作

原理说明

Nginx 默认开启 server_tokens on,会在两个位置泄露信息:一是响应头 Server: nginx/1.24.0,直接给出精确版本号;二是 404、50x 等默认错误页脚注中的 nginx/1.24.0 字样,部分发行版编译包甚至附带 OS 标识。攻击者拿到精确版本后,可在漏洞库中筛出该版本未修复的 CVE,配合 PoC 定向利用,攻击成本大幅降低。版本号隐藏属于典型的攻击面收缩措施:不修复漏洞本身,但让攻击者无法低成本定位漏洞。

此外,反向代理或 FastCGI 场景下,后端 PHP 常通过 X-Powered-By: PHP/8.2.1 响应头泄露应用层版本,需要一并清理。

操作步骤

1. 关闭 server_tokens

http {
    server_tokens off;
}

修改后 Server 头只剩 nginx,错误页脚注同样只显示 nginx 不带版本。

2. 隐藏 PHP 版本响应头

http {
    fastcgi_hide_header X-Powered-By;
}

3. 彻底改写 Server 头(可选)

若安全基线要求 Server 头不出现 nginx 字样,需安装 headers-more 模块:

# CentOS/RHEL
yum install -y nginx-module-headers-more
# Ubuntu/Debian
apt install -y libnginx-mod-http-headers-more-filter

在 http 块中加载后改写:

load_module modules/ngx_http_headers_more_filter_module.so;
http {
    more_set_headers "Server: WebServer";
}

注意:动态模块必须与当前 Nginx 版本严格匹配,优先用包管理器安装配套模块包,手工编译极易导致 nginx -t 报模块不兼容。

4. 自定义错误页

server {
    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;
    location = /404.html { root /usr/share/nginx/html; internal; }
    location = /50x.html { root /usr/share/nginx/html; internal; }
}

server_tokens off 后默认错误页已不带版本号,但自定义错误页可进一步避免暴露服务器内部路径与模块信息。

5. 重载配置

nginx -t && nginx -s reload

配置验证

curl -sI https://www.example.com | grep -i server
# 期望输出:Server: nginx(无版本号)
# 配合 headers-more 后输出:Server: WebServer

再访问一个不存在的路径触发 404,确认错误页脚注无 nginx/1.24.0 字样;用 curl -sI https://www.example.com | grep -i powered 确认 X-Powered-By 已消失。

常见问题

FAQ 1:server_tokens off 后 502 页面仍显示版本号?

常见于反向代理场景:502 页面由上游生成并透传回来,http 块的 server_tokens 只影响 Nginx 自身生成的响应。需在对应 server 或 location 块补充 proxy_intercept_errors on; 并定义 error_page 让 Nginx 接管错误页,或对上游响应同样执行 more_clear_headers 清理。

FAQ 2:安装 headers-more 模块后 nginx -t 报 module is not binary compatible?

原因是模块编译时的 Nginx 版本、编译参数与运行中二进制不一致。先用 nginx -V 记录当前编译参数,通过源码目录以相同参数 ./configure --add-dynamic-module=... 编译模块,或直接安装发行版仓库中与当前 nginx 包配套的模块包。禁止将 A 版本编译的 .so 拷贝到 B 版本加载。

FAQ 3:隐藏版本号是不是就安全了?

不是。版本隐藏只增加攻击者的信息获取成本,漏洞本身仍需补丁修复。正确做法是把版本隐藏作为基线项,同时定期升级 Nginx 到最新稳定版,两者配合才能真正收缩攻击面。

总结

Nginx 版本号隐藏是成本最低、收益确定的基线加固项:server_tokens off 一行配置即可消除响应头与错误页的版本泄露,fastcgi_hide_header 清理 PHP 指纹,headers-more 模块按需彻底改写 Server 头。配置后务必用 curl 复核响应头与错误页两处,反向代理场景另需关注上游错误页透传问题。