
核心要点(TL;DR)
- 默认 server 块与 server_tokens on 是最高频的 Nginx 信息泄露源,应优先关闭。
- TLS 只保留 1.2/1.3,加密套件按 Mozilla 中间兼容档配置并启用 OCSP Stapling。
- 用 openssl s_client 与 nmap ssl-enum-ciphers 验证加固结果,不验证等于没加固。
- 安全响应头与请求体限制需在 http 块统一配置,避免逐站点遗漏。
很多站点上线时只关心 Nginx 能不能跑通,忽略了默认配置本身就是一份「攻击说明书」:版本号外泄、弱加密套件开放、默认 server 块接管未知域名、目录列表可浏览。这些问题不会让业务立刻挂掉,却会在扫描器眼里亮成红灯。本文按「错误现象—排查命令—修复配置」的顺序,给出可直接套用的 Nginx 安全配置与 TLS 加固参数模板,照着做半小时内可完成一轮加固。
一、先看清:Nginx 最常见的安全配置错误
按危害排序,以下六类问题出现频率最高,建议逐条对照 nginx.conf 自查:
| 错误项 | 风险 | 典型表现 |
|---|---|---|
| server_tokens 未关闭 | 版本指纹泄露 | 响应头含 nginx/1.18.0 |
| 默认 server 块缺失 | 未知 Host 被正常站点接管 | IP 直访返回业务页 |
| autoindex on | 目录遍历、源码泄露 | 路径末尾加 / 可列文件 |
| 仅开 TLS 1.0/1.1 | 降级与中间人风险 | 扫描器报弱协议 |
| 弱加密套件开放 | RC4/3DES 可被破解 | ssl-enum-ciphers 出现 CBC |
| 缺安全响应头 | 点击劫持、XSS 放大 | 无 CSP、X-Frame-Options |
二、信息泄露与默认块:先堵住最低成本的入口
第一步在 http 块统一关闭版本号与目录列表,并补一个拒绝未知 Host 的默认 server:
http {
server_tokens off;
autoindex off;
client_max_body_size 10m;
server {
listen 80 default_server;
listen 443 ssl default_server;
server_name _;
ssl_reject_handshake on; # Nginx 1.19.4+
return 444;
}
}
验证方式:curl -I http://服务器IP 应直接断开或无业务响应;curl -I https://你的域名 的 Server 头不再带版本号。若使用旧版本 Nginx,可用自签证书占位替代 ssl_reject_handshake。
三、TLS 加固参数模板:协议、套件与证书链
核心原则只有三条:只留 TLS 1.2/1.3、只允许前向安全的 AEAD 套件、证书链必须完整。下面这份模板可直接放进 http 块或独立 ssl.conf 后 include:
ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d; ssl_session_tickets off; ssl_stapling on; ssl_stapling_verify on; resolver 223.5.5.5 1.1.1.1 valid=300s; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Content-Type-Options nosniff always; add_header X-Frame-Options SAMEORIGIN always; add_header Referrer-Policy strict-origin-when-cross-origin always;
注意两点:ssl_ciphers 对 TLS 1.3 不生效,1.3 套件由 OpenSSL 管理,无需也无法在此禁用;HSTS 首次上线建议先用 max-age=300 观察一周,确认全站 HTTPS 与子域覆盖后再拉长。
四、分步排查:三条命令定位问题
- 协议与证书链:
openssl s_client -connect example.com:443 -servername example.com -tls1_2,观察 Verify return code 是否为 0,链是否完整。 - 套件枚举:
nmap --script ssl-enum-ciphers -p 443 example.com,确认无 TLS 1.0/1.1、无 RC4/3DES/CBC 套件。 - 配置语法与生效:
nginx -t通过后再nginx -s reload,用curl -I核对响应头是否真的下发。
常见坑:add_header 在 location 块中会覆盖上层配置,若某 location 单独写了 add_header,http 块的安全头将全部失效,需在该 location 内重复声明。
五、反向代理与请求侧加固
代理场景要同时处理真实 IP 与请求体限制:
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_read_timeout 60s;
}
# 后端还原真实 IP(只信任代理网段)
set_real_ip_from 10.0.0.0/8;
real_ip_header X-Forwarded-For;
set_real_ip_from 必须只填可信代理网段,否则攻击者可伪造 XFF 绕过限流。同时在 http 块设置 client_body_timeout、client_header_timeout 与 limit_req_zone,防止慢速攻击与暴力刷接口。
六、上线前检查清单
- server_tokens off 且默认 server 返回 444;
- 仅 TLS 1.2/1.3,ssl-enum-ciphers 无弱套件;
- 证书链完整、OCSP Stapling 生效;
- HSTS、nosniff、X-Frame-Options 已下发且未被 location 覆盖;
- autoindex 关闭,敏感路径(.git、.env、备份文件)返回 403;
- 请求体大小、超时与限流已配置。
若希望把上述规则做成持续防护而非一次性配置,可关注 AegisX 在 TLS 合规检测、配置基线核查与异常请求拦截方面的能力,把「上线前自查」变成「运行中持续校验」。
行动建议:今天先做两件事——关闭 server_tokens 并补默认 server 块,替换 TLS 参数模板;明天用 nmap 与 SSL Labs 复测,把检查清单固化进发布流程。安全配置的价值不在写得多漂亮,而在每次变更后仍能被验证。
常见问题(FAQ)
Nginx 怎么隐藏版本号?改了 server_tokens off 为什么还显示 nginx?
server_tokens off 只能让错误页与响应头中的版本号变为 nginx,无法完全隐藏服务标识。若要彻底不暴露,可编译时使用 --build 参数修改,或用第三方模块 headers-more 清除 Server 头。更实际的做法是关闭版本号并配合统一错误页,降低攻击者按版本匹配漏洞的效率,同时不影响正常业务。
TLS 1.3 已经默认安全,还需要配置 ssl_ciphers 吗?
需要,但优先级不同。TLS 1.3 的套件由 OpenSSL 内部管理,ssl_ciphers 只作用于 TLS 1.2 及以下。因此加固重点是显式禁用 TLS 1.0/1.1、移除 RC4/3DES/EXPORT 等弱套件,并为 1.2 指定 ECDHE + AES-GCM 组合,同时开启 ssl_prefer_server_ciphers on,避免客户端选择弱套件。
配置了 HSTS 后网站打不开或无法回退 HTTP 怎么办?
HSTS 会让浏览器在 max-age 内强制走 HTTPS,配置错误时确实难以回退。建议首次上线先用 max-age=300 短周期观察,确认全站 HTTPS、证书链完整、子域都已覆盖后再提升到一年并加 includeSubDomains。若已误配,只能等 max-age 过期或引导用户清浏览器 HSTS 记录,因此务必先在测试环境验证。
Nginx 反向代理后如何拿到真实客户端 IP 做限流?
默认后端只看到代理 IP,需在代理层设置 proxy_set_header X-Real-IP $remote_addr 与 X-Forwarded-For,后端再用 real_ip_header 与 set_real_ip_from 信任代理网段还原。注意 set_real_ip_from 只填可信代理 IP,否则攻击者可伪造 XFF 头绕过限流与封禁,这是常见的安全配置错误。
怎么快速验证 Nginx 的 TLS 配置是否达标?
用 openssl s_client -connect 域名:443 -tls1_2 检查协议与证书链,用 nmap --script ssl-enum-ciphers -p 443 域名 枚举可用套件,再配合 SSL Labs 在线评分交叉验证。重点确认不支持 TLS 1.0/1.1、无 RC4/3DES、证书链完整、OCSP Stapling 生效,验证通过后再发布。