记录一下那天晚上的排查过程。Ubuntu 22.04 上 nginx 1.24 把 ssl_ciphers 收紧到只留 GCM 套件,几个老客户端和 Java 8 的 HttpURLConnection 连上来直接失败,服务端 error.log 里是 SSL_do_handshake() failed。
刚开始盯着「OpenSSL 的安全级别调到 4,偏弱的套件被整个过滤掉」,折腾了半个多小时,排掉了。
真正麻烦的地方在于,几个原因的现象几乎一样。ssl_ciphers 只管 TLS 1.2 及以下,TLS 1.3 的套件由另一组参数控制。也可能是客户端只支持 TLS 1.0 和 CBC 套件,服务端把它们全禁了。
还有一种情况,证书是 RSA 但套件里只剩 ECDHE-ECDSA,密钥交换算法对不上。
动手时先看客户端支持什么
openssl s_client -connect 127.0.0.1:443 -servername demo.example.com -tls1_2 </dev/null 2>&1 | grep -E 'Cipher|Protocol'
再往下列出服务端实际能协商的套件
nmap --script ssl-enum-ciphers -p 443 demo.example.com | head -30
补一组兼容套件并保留 TLS 1.3
printf '%s
' 'ssl_protocols TLSv1.2 TLSv1.3;' 'ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5;' 'ssl_prefer_server_ciphers on;' > /etc/nginx/conf.d/tls.conf
reload 后用老客户端复测
nginx -t && nginx -s reload && openssl s_client -connect 127.0.0.1:443 -tls1_2 </dev/null 2>&1 | grep 'Cipher is'
隔了一天再看,现象没变,说明不是偶发。
改完先别撤,确认这几项。老客户端握手成功,openssl 输出里有可用的 Cipher,error.log 不再出现 no shared cipher。
补一句。收紧套件前先按 ssl_protocol 统计客户端版本分布;TLS 1.3 的套件不受 ssl_ciphers 控制,要改得用 ssl_conf_command。改动前把原配置备份一份,出问题能马上回滚,这比任何技巧都实用。
