ssl_reject_handshake是Nginx 1.19.4+引入的安全特性,用于在TLS握手阶段直接拒绝不匹配server_name的请求,不建立SSL连接、不返回证书、不进入HTTP流程,专防未定义域名的SSL探测。

ssl_reject_handshake 是 Nginx 1.19.4+ 引入的安全特性,用于在 TLS 握手阶段直接拒绝不匹配 server_name 的客户端请求,**不建立 SSL 连接、不返回任何证书、不进入 HTTP 处理流程**。它主要解决的是“未定义域名的 SSL 探测”问题——即攻击者或扫描器通过 SNI(Server Name Indication)发送任意域名(如 scan.example.com、test.bad.com)尝试建立 HTTPS 连接,探测服务器配置、证书信息或服务指纹。
为什么需要 ssl_reject_handshake?
传统 Nginx 配置中,若未为某个 SNI 域名显式定义 server 块,Nginx 默认会使用第一个匹配的 HTTPS server(即“默认 server”)响应。这会导致:
- 暴露默认证书(可能含内部域名或过期证书),泄露敏感信息
- 被误判为托管了不存在的域名,影响资产测绘和合规审计
- 增加不必要的 TLS 握手开销和日志噪音
- 无法区分恶意探测与真实业务流量
如何启用并正确配置?
该指令必须放在 http 或 stream 上下文中(推荐 http),且仅对启用了 SSL 的 server 块生效:
http {
ssl_reject_handshake on; # 全局开启:所有 HTTPS server 默认拒绝未知 SNI
<pre class="brush:php;toolbar:false;">server {
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# 此 server 只响应 SNI 为 example.com 或 www.example.com 的握手
}
# 不再需要“default_server”来兜底;未知 SNI 将被内核级拒绝
}
注意:
- 开启后,Nginx 不再回退到任意默认 server,而是向客户端发送
handshake_failurealert 并立即关闭连接 - 已存在的
default_server配置会被忽略(除非显式关闭ssl_reject_handshake) - 它不影响 HTTP(非 SSL)请求,也不影响已建立连接后的 Host 头校验
配合其他机制提升防护效果
ssl_reject_handshake 是第一道防线,建议组合使用:
-
严格 SNI 白名单:只在
server_name中列出生产使用的域名,避免通配符泛滥(如*.example.com会接受所有子域,削弱防护) -
禁用不安全协议和加密套件:在 server 块中设置
ssl_protocols TLSv1.2 TLSv1.3;和强 cipher suite - 访问日志过滤:配合 log_format 记录 $ssl_server_name,便于识别异常 SNI 请求(虽然握手被拒,但部分日志仍可捕获 SNI)
- 防火墙层限速:对高频 TLS 握手失败 IP 做速率限制,防暴力探测
验证是否生效
使用 OpenSSL 手动测试未知域名的 SNI 握手:
openssl s_client -connect your-server.com:443 -servername evil.test.com -tls1_2
若配置正确,输出中应出现:
139639502237056:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:../ssl/record/rec_layer_s3.c:1544:SSL alert number 40
而不是返回证书信息或成功建立连接。也可用 tcpdump 观察是否只有 ClientHello 后即收到 Alert 包,确认无证书下发。










