ssl_handshake_timeout仅作用于已建TCP连接但未完成TLS握手的场景,超时后释放连接;不防SYN Flood、已完成握手的空闲连接及Slowloris等应用层攻击。

直接设一个合理值(比如 15–30 秒),就能让未完成 TLS 握手的连接及时释放,避免 worker 进程被长期占用。它不防所有攻击,但对“只发 ClientHello 就停住”的慢握手行为非常有效。
它管什么、不管什么
ssl_handshake_timeout 只作用于已建立 TCP 连接、但尚未完成 TLS 握手的连接。一旦 ServerHello 发出、密钥交换开始,这个超时就不再起效。
它不管:
- TCP 层的 SYN Flood(得靠系统级 tcp_syncookies 或防火墙)
- 已完成握手但后续不发 HTTP 请求的空闲连接(那是 keepalive_timeout 的事)
- 应用层慢速攻击,比如 Slowloris(需 client_header_timeout 配合)
怎么配才真正起作用
这个指令必须出现在启用 SSL 的 server 块里,且 listen 指令要带 ssl 参数,否则不生效。推荐写法:
server {
listen 443 ssl;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
ssl_handshake_timeout 20s; # 公网服务常用值
}全局配置可放在 http 块中,但建议按业务差异化设置——比如 CDN 回源用 10s,面向海外用户的主站用 25s。
别踩这些坑
设得太短(如 ≤2 秒)反而伤业务:
- 跨洲际或移动弱网用户容易握手失败,表现为“部分用户打不开”
- Nginx 频繁分配又释放 socket 和内存,引发上下文切换抖动
- 旧版 Android WebView、IoT 设备等 TLS 实现较慢,易被误杀
设得太长(如 >60 秒)等于没设——默认值就是 60 秒,失去防护意义。
搭配其他配置效果更好
单靠 handshake timeout 不够,建议同步做这几件事:
- 禁用 TLS 1.0/1.1,强制 ssl_protocols TLSv1.2 TLSv1.3,减少握手开销
- 调高 worker_connections 并开启 multi_accept,避免单次 accept 处理过多新连接
- 监控日志里的 SSL_do_handshake() failed 错误频次,结合地区、UA 判断是否真有攻击
- 配合网络层限速(如 fail2ban + $ssl_server_name 日志)封禁高频异常握手 IP


















