Nginx 通过 ssl_reject_handshake on 在 TLS 握手初期拒绝连接,防止证书信息泄露;需满足版本≥1.19.4、置于 http 块内、监听启用 SSL 且 server 中配置有效证书。

直接用 IP 访问 HTTPS 服务时,Nginx 默认会返回某个 server 块的证书——哪怕你没配域名,它也会“递出”第一个 SSL 配置里的证书。攻击者或扫描器(如 Censys)拿到证书后,立刻就能提取 SAN 或 CN 字段,反推出你的真实域名和源站 IP。这不是警告,是事实性泄露。
而 ssl_reject_handshake on 的作用,就是在 TLS 握手最开始阶段(ClientHello 后)就拒绝连接,不发证书、不协商密钥、不进入后续流程,从协议层切断信息出口。
必须满足的前提条件
这个指令不是加了就生效,它有硬性依赖:
- Nginx 版本 ≥ 1.19.4(推荐使用 1.25.5 或更新稳定版)
- 配置位置必须在
http { ... }块内(不能只放在某个 server 里) - 仅对启用了 SSL 的监听生效(即
listen 443 ssl或listen [::]:443 ssl) - server 块中需明确包含
ssl_certificate和ssl_certificate_key,否则 Nginx 启动会报错
标准配置写法(推荐)
以下配置适用于绝大多数生产环境,兼顾安全与简洁:
http {
ssl_reject_handshake on;
<pre class='brush:php;toolbar:false;'>server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
server_name _;
# 必须提供合法证书路径(可复用已有证书,也可单独生成轻量自签名)
ssl_certificate /etc/nginx/ssl/default.crt;
ssl_certificate_key /etc/nginx/ssl/default.key;
return 444; # 连接立即关闭,不返回任何响应体
}}
注意:server_name _ 是 Nginx 识别“无效主机名”的约定写法;default_server 标识该块为 443 端口的兜底入口;return 444 是辅助手段,确保即使握手被绕过(极罕见),HTTP 层也不响应。
常见误区与避坑点
实际部署中这几个细节最容易出错:
- 不要把 ssl_reject_handshake 放进 stream 上下文:它只在 HTTP 模块中有效,stream 是四层代理,不解析 SNI,无法做域名级拦截
- 已存在的 default_server 不会自动失效:如果你之前配了带证书的 default_server 但没开此指令,它仍会照常发证书;启用后,该块行为变为“拒绝握手”,原证书不再外泄
-
通配符 server_name 会削弱防护:比如写成
server_name *.example.com;,那么test.example.com、dev.example.com全部会被接受——这等于主动开放子域探测面 -
HTTP 请求不受影响:该指令只管 TLS 握手,80 端口的 IP 访问仍需单独用
return 444或deny all控制
验证是否生效
用 OpenSSL 手动模拟一次 TLS 握手,观察是否被内核级中断:
openssl s_client -connect your.ip.address:443 -servername example.com 2>/dev/null | head -10
如果看到类似 write:errno=0 或连接直接重置(no response),说明握手被拒绝成功;若出现 subject=CN=... 或证书内容,则配置未生效或被其他 server 块覆盖。


















