必须在http块顶层加server_tokens off;才能隐藏Nginx版本号,但Server头仍存在;需用more_clear_headers或more_set_headers彻底移除,错误页中的“nginx”须重编译源码或由反向代理过滤。

必须在 http 块顶层加 server_tokens off;,否则版本号仍会出现在错误页和响应头里——这是最常被漏掉的一处。
移除 Server 响应头与错误页中的 Nginx 标识
默认的 Server: nginx/1.24.0 是攻击者扫描的第一手线索。仅靠 server_tokens off; 只能隐藏版本号,但 Server: nginx 依然存在。要彻底抹除,需额外模块支持:
- 安装
ngx_http_headers_more_module(需重新编译或使用预编译包),然后在http块中添加:more_clear_headers "Server";
- 若无法重编译,可在
http块中用more_set_headers伪装:more_set_headers 'Server: WebServer';
- 错误页面(如 404、50x)里的文字“nginx”来自源码硬编码,必须修改
src/http/ngx_http_special_response.c并重编译——线上已运行的实例不建议临时动源码,优先靠反向代理层(如 CDN 或前置 LB)过滤响应体
限制 HTTP 方法:只允许 GET、HEAD、POST
开放 TRACE、OPTIONS、PUT、DELETE 等方法极易被用于探测、缓存投毒或 SSRF。Nginx 不提供“白名单式”方法控制,只能用 limit_except 显式拒绝:
- 在
location /或敏感location块内写:limit_except GET HEAD POST { deny all; } - 注意:
HEAD必须显式列出,否则会被limit_except拒绝——它不是GET的子集 - 该指令不作用于
location ~ \.php$等正则匹配块,若后端是 PHP-FPM,还需在 FastCGI 层或应用层二次校验
禁止访问敏感文件与目录的最小化规则
攻击者常通过遍历路径尝试读取 .git/config、config.php.bak、error.log 等。Nginx 的 location 匹配是前缀+正则混合机制,顺序和贪婪度极易出错:
- 把敏感路径拦截放在所有
location /规则之前,避免被覆盖:location ~* \.(git|svn|hg|bzr|log|bak|swp|swo|orig|conf|ini|yml|yaml|env)$ { deny all; }<br>location ~* ^/\. { deny all; } -
~*是大小写不敏感正则,比=或^~低优先级,所以必须确保它不被更长的前缀匹配提前截断 - 上传目录(如
/uploads/)需单独放开执行权限隔离:location ^~ /uploads/ { add_header Content-Disposition "attachment"; # 禁止解析脚本<br> location ~ \.(php|pl|py|jsp|sh|cgi)$ { deny all; } }
user 指令配置与系统级权限对齐
user 指令写在 nginx.conf 最顶层才生效,且该用户必须对静态资源有「只读」、对日志目录有「追加写」权限,否则 worker 启动即失败:
- 创建专用用户:
useradd -r -s /sbin/nologin -M nginx(-M省略家目录,-r标记为系统用户) - 确认
nginx.conf开头有:user nginx nginx;
- 设权示例:
chown -R root:nginx /usr/share/nginx/htmlchmod -R 750 /usr/share/nginx/htmlfind /usr/share/nginx/html -type f -exec chmod 640 {} \; - 日志目录权限易错:
/var/log/nginx需root:nginx+750,否则 worker 无法创建新日志文件
真正难的不是写几行配置,而是让每条规则在真实请求路径中按预期顺序匹配、不被覆盖、不因权限错位静默失败。上线前务必用 curl -I、curl -v 和故意构造的恶意路径(如 /test/.git/config)逐条验证,而不是只信 nginx -t 语法正确。











