Nginx 的 ssl_reject_handshake on 指令可在 TLS 握手初期拒绝非法 SNI 请求,需置于 http 块顶层,配合显式 server_name 和重载生效,结合 80 端口拦截、精简 SAN、日志监控等实现纵深防护。

直接用 IP 访问 HTTPS 服务,是常见的信息探测入口。Nginx 的 ssl_reject_handshake on 指令能在 TLS 握手最前端就拒绝这类请求,不发证书、不建连接、不留痕迹——这是从协议层切断泄露路径的高效方式。
必须放在 http 块顶层启用
该指令只在 HTTP 模块生效,且不能写在 server 块里,也不支持 if 判断或条件启用。正确做法是在 nginx.conf 的 http 块开头直接添加:
ssl_reject_handshake on;- 它只对启用了 SSL 的
listen 443 ssl监听生效,不影响普通 HTTP 请求 - 无需重启整个 Nginx,重载配置(
nginx -s reload)即可生效
每个 HTTPS server 必须显式列出合法域名
启用后,Nginx 会严格比对客户端在 TLS 握手中声明的 SNI(Server Name Indication)。只有被 server_name 明确匹配的域名才允许继续握手:
- ✅ 正确写法:
server_name example.com www.example.com api.example.com; - ❌ 禁止通配符:
server_name *.example.com;—— 这会让所有子域通过,等于放弃防护 - ❌ 不要保留“兜底 default_server”:带证书的默认 HTTPS server 会继续发证,抵消拦截效果
验证是否真正生效
别只看配置文件,要用真实工具验证行为是否符合预期:
- 用 OpenSSL 模拟非法 SNI:
openssl s_client -connect 1.2.3.4:443 -servername fake.test.com -tls1_2
成功拦截时,输出中会出现SSL routines::UNRECOGNIZED_NAME,且没有 Certificate: 段 - 用 curl 测试 IP 直连:
curl -vI https://1.2.3.4
应卡在 TLS 握手阶段失败,看不到 Server Hello,浏览器会报ERR_SSL_UNRECOGNIZED_NAME_ALERT - 再用合法域名测试:
openssl s_client -connect 1.2.3.4:443 -servername example.com
应正常完成握手并显示证书信息,确认业务不受影响
搭配其他措施避免绕过
单靠 ssl_reject_handshake 不足以覆盖全部风险,建议同步加固:
- 对 HTTP 默认站点也做拦截:
server { listen 80 default_server; return 444; },防止 80 端口暴露服务指纹 - 精简证书 SAN 列表:正式证书只包含生产必需域名,避免 Let’s Encrypt 申请时用
--standalone暴露临时端口 - 记录可疑 SNI:
log_format main "... $ssl_server_name ...";,便于分析探测模式并配合限速策略


















