ssl_reject_handshake可阻止IP直连HTTPS时泄露域名:需Nginx≥1.19.4、启用stream_ssl_preread模块,在default_server的443 server块中配置且不设证书,实现TLS层拒绝握手。

直接用 IP 地址访问 HTTPS 服务时,Nginx 默认会返回证书(哪怕只是默认站点),导致域名和源站 IP 关联暴露——ssl_reject_handshake 就是为切断这个泄露链而设的:它不发证书、不响应握手,从 TLS 层就拒绝连接。
确认 Nginx 版本与模块支持
该指令属于 stream 模块,但实际用于 HTTPS 场景时,需配合 http 模块中的 server 块(注意不是 stream 块)。必须满足:
- Nginx ≥ 1.19.4(官方引入版本)
- 编译时启用了
--with-stream_ssl_preread_module(多数主流发行版及宝塔、Oneinstack 等一键脚本已默认包含) - 配置位于
server { listen 443 ssl; ... }块内,且该块用于匹配未指定域名的请求(即 default_server)
配置一个专用的“拒接默认站点”
不要复用已有网站的 server 块。新建一个仅监听 443、不带有效 server_name 的 server,专用于拦截 IP 访问:
server {
listen 443 ssl default_server;
ssl_reject_handshake on;
<pre class="brush:php;toolbar:false;"># 不需要配置证书、密钥、SSL参数
# 也不需要 return 444 或其他 HTTP 响应}
关键点:
-
default_server确保它兜底所有未被其他server_name匹配的 443 请求(含 IP 直连) - 该块中不能出现
ssl_certificate或ssl_certificate_key,否则 Nginx 启动会报错 - 无需 reload 全局 SSL 配置,只要该 server 块生效即可
验证是否生效
用 curl 或浏览器测试 IP 的 HTTPS 访问:
-
curl -vI https://你的服务器IP—— 应在 TLS 握手阶段失败,看不到 Server hello,更看不到证书信息 - 浏览器访问会显示类似 ERR_SSL_UNRECOGNIZED_NAME_ALERT(Chrome)或 SSL_ERROR_UNRECOGNIZED_NAME_ALERT(Firefox)
- 用
openssl s_client -connect 你的IP:443 -servername example.com测试正常域名访问,应仍可成功(说明未影响合法流量)
搭配其他防护避免绕过
仅靠 ssl_reject_handshake 不足以完全防 IP 泄露,需组合使用:
-
禁用默认 HTTP 站点:对
listen 80 default_server也设置return 444,防止 HTTP 层暴露 -
收紧证书信息:确保正式证书不包含泛域名或无关子域名;申请 Let’s Encrypt 时避免用
--standalone暴露源站 IP 验证 -
缩短握手超时:在 server 块中加
ssl_handshake_timeout 15s;,防止慢握手耗尽资源 -
屏蔽扫描器 IP:结合
geo+map+deny,对高频访问 IP 直接 TCP 拒绝(需在 listen 指令前生效)


















