Nginx 安全配置错误排查与 TLS 加固参数模板实战 核心要点图解,默认 server 块与 server_tokens on 是最高频的 Nginx 信息泄露源,应优先关闭。;TLS 只保留 1.2/1.3,加密套件按 Mozilla 中间兼容档配置并启用 OCSP Stapling。;用 openssl s_client 与 nmap ssl-enum-ciphers 验证加固结果,不验证等于没加固。;安全响应头与请求体限制需在 http 块统一配置,避免逐站点遗漏。
Nginx 安全配置错误排查与 TLS 加固参数模板实战 · 核心要点一图读懂(AegisX)

核心要点(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 与子域覆盖后再拉长。

四、分步排查:三条命令定位问题

  1. 协议与证书链:openssl s_client -connect example.com:443 -servername example.com -tls1_2,观察 Verify return code 是否为 0,链是否完整。
  2. 套件枚举:nmap --script ssl-enum-ciphers -p 443 example.com,确认无 TLS 1.0/1.1、无 RC4/3DES/CBC 套件。
  3. 配置语法与生效: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 生效,验证通过后再发布。