关闭 TLS 1.0 / 1.1,只留 1.2 和 1.3
服务器还在使用 TLS 1.0 或 1.1 协商连接。
TLS 1.0 和 1.1 在 2020 年就被 Chrome、Firefox、Safari、Edge 集体废弃了,PCI DSS 也要求禁用 TLS 1.0。现在正确的配置是只保留 TLS 1.2 和 1.3。
改动很小 —— nginx 一行,Apache 一行。真正需要判断的是兼容性代价:确认没有还在用老客户端的调用方,再动手。
改配置
nginx
ssl_protocols TLSv1.2 TLSv1.3;
# TLS 1.3 时代,让客户端选套件通常比服务器强制更好
ssl_prefer_server_ciphers off;TLS 1.3 需要 nginx 1.13.0 以上并链接 OpenSSL 1.1.1 以上。nginx -V 能看到编译时用的 OpenSSL 版本;如果偏低,写上 TLSv1.3 不会报错,但也不会生效。
Apache
SSLProtocol -all +TLSv1.2 +TLSv1.3-all 先全部关掉再逐个打开,比逐个 -TLSv1 排除更不容易漏 —— 后者在升级 Apache 后新增的协议版本会默认打开。
密码套件要不要一起调
多数情况下不用。手写套件列表是最容易配错、也最容易过时的一处:抄一份两年前的「安全配置」,往往同时关掉了现代客户端需要的套件。需要调的时候用 Mozilla 的 intermediate 档配置生成,不要自己列。
改完照例先测语法再重载:
nginx -t && nginx -s reload
# 或
apachectl configtest && apachectl graceful谁会被挡在外面
这是唯一需要认真评估的部分。只支持 TLS 1.0/1.1 的客户端:
| 客户端 | 情况 |
|---|---|
| Android 4.4 及更早 | 系统栈不支持 TLS 1.2 |
| IE 10 及更早(Windows 7) | 不支持;IE 11 支持但可能需要手动勾选 |
| Windows XP / Vista | 系统层面就没有 TLS 1.2 |
| Java 6、Java 7 | 支持但默认不启用,需要调用方改启动参数 |
| .NET Framework 4.5 及更早 | 默认不用 TLS 1.2,需要调用方改代码 |
| 很老的 curl / OpenSSL 0.9.8 | 不支持 |
对面向公众的网站来说,这几类加起来的占比现在已经可以忽略。真正的风险在服务端到服务端的调用:某个合作方的老系统、某台多年没动过的内部机器、某个用旧 Java 写的对接程序。这些不会出现在浏览器统计里,出问题时也不会有人来告诉你,只会静默失败。
所以顺序是:先在访问日志里确认还有没有 TLS 1.0/1.1 的连接,再改。nginx 可以把协议版本打进日志:在 log_format 里加上 $ssl_protocol,观察几天。
log_format tlsver '$remote_addr $ssl_protocol $ssl_cipher "$request"';
access_log /var/log/nginx/access.log tlsver;怎么确认真的关掉了
逐个版本单独建连,最直接:
# 应该失败(handshake failure)
openssl s_client -tls1 -connect example.com:443 -servername example.com </dev/null
openssl s_client -tls1_1 -connect example.com:443 -servername example.com </dev/null
# 应该成功
openssl s_client -tls1_2 -connect example.com:443 -servername example.com </dev/null
openssl s_client -tls1_3 -connect example.com:443 -servername example.com </dev/null如果本机是 OpenSSL 3.x,前两条可能因为本机的安全等级就拒绝了,而不是因为服务器拒绝 —— 这两种失败长得很像。加上 -cipher 'DEFAULT@SECLEVEL=0' 可以把本机限制放开,让失败真正来自对端。
为什么本站的检测只报「协商到的版本」
值得说清楚,因为它决定了这个结论该怎么用:一次握手只会协商出一个版本,而我们提供的是现代版本,所以正常情况下会协商到 TLS 1.2 或 1.3。也就是说 ——
- 检测报出
TLSv1或TLSv1.1,说明服务器最高只支持到这个版本,问题确凿。 - 检测报出
TLSv1.3,只能说明它支持 1.3,不能说明它已经关掉了 1.0 —— 一台同时支持 1.0 到 1.3 的服务器在我们这里看起来是干净的。
要判断第二种情况,必须每个版本单独建一次连接,也就是上面那四条命令。我们没有把它做进默认检测,是因为那意味着每次检测多开四个连接、对被检测的服务器多四倍的握手成本,而这一项并不是导致访客打不开网站的故障。
常见问题
检测一下你自己的域名
免登录,一次真实的 TLS 握手,直接给出结论:还有多少天到期、证书链是否完整、是否包含这个域名。
需要一张新证书?本站提供基于 Let's Encrypt 的免费签发,支持泛域名。
了解免费证书其他排错指南
- 证书过期了怎么办浏览器拦下访问,提示证书已过期或连接不是私密连接。
- 证书快到期了:先分清是没续期,还是续了没部署证书还没过期,但剩余天数已经不多了。
- 证书还没到生效时间:多半是时钟不对证书的生效时间还没到,被判定为无效。
- 证书透明度日志里出现了没见过的证书监控期间,域名下出现了不是本站签发的新证书。
- 无法连接:证书检测连不上服务器时的排查顺序检测连不上服务器,没能拿到证书。
- 「您的连接不是私密连接」:先找错误代码,再决定修哪里浏览器弹出红色警告拦下访问,但不知道属于哪一种证书问题。
- 证书不包含这个域名:ERR_CERT_COMMON_NAME_INVALID 的几种成因浏览器提示证书不适用于该网站,或者拿到了另一个站点的证书。
- 电脑打得开、手机 App 报证书错误:证书链缺少中间证书电脑浏览器打得开,手机 App、curl 或 Java 客户端却报证书错误。
- OCSP stapling:开了能快一点,不开也不算故障没有启用 OCSP stapling,首次握手会稍慢一些。
- 证书被吊销,或者链验证没通过证书被吊销,或者链验证没有通过。
- 自签名证书:什么时候没问题,什么时候必须换证书是自己签给自己的,浏览器不信任。
- 证书链追溯不到受信任的根:新根交叉签名与私有 CA浏览器打得开,curl、旧安卓或 Java 客户端却说找不到颁发者证书。
- RSA 密钥长度不足:为什么现在才被提醒证书的 RSA 密钥长度低于 2048 位。
- 泛域名证书为什么不覆盖主域名子域名都正常,直接访问主域名却报证书错误。
Last updated on