前段时间遇到了一个问题,采用 Let’s Encrypt 证书部署 https 的网站,唯独在 IOS 平台访问极慢,会卡个三五秒空白页。通过查询发现,有人遇到过一样的问题,原因是 IOS 平台会在用户通过 https 协议访问网站时,实时校验证书状态(据称 MacOS 也会,博主手上没有设备)。也就是说,在 ssl 握手拿到证书后,不会直接和服务器进行下一步交互,而是转头去请求对应 CA 的实时校验地址,核实证书状态。

IOS、MacOS 访问慢的原因

好巧不巧,这个实时校验地址可能会由于众所周知的原因抽风。那么这个地址在哪里呢?很多文章会提到这个地址: http://ocsp.int-x3.letsencrypt.org 。但其实该项信息就包含在证书信息里面,且不应该假定这个地址是不变的。例如我博客域名 quarkay.com 就是使用的 Let's Encrypt 证书,查看证书信息会发现地址现在已经更新了,变成了: http://r3.o.lencr.org 。如下图:

quarkay.com Let's Encrypt 证书 OCSP 地址信息截图

请求这个地址并校验证书,当然需要按照规则来,于是 OCSP 就出现了,翻译过来叫“在线证书状态协议”,可谓是非常的见名知义。但是假如这个地址抽风,校验过程就卡住了,于是对用户来说就卡在空白页面了。好在 IOS 和 MacOS 对此都有个超时机制,超时的话就不校验了,接着进行下一步访问动作。

基本可以解决的解决方案

这个问题拖到今天已经自动缓解了,甚至基本自动解决了,所以说,等等党必将胜利?

维基百科:

2020年4月2日,防火长城对Let's Encrypt的OCSP服务器(ocsp.int-x3.letsencrypt.org)所使用的Akamai CDN域名a771.dscq.akamai.net进行了DNS污染,导致部分浏览器首次访问使用Let's Encrypt证书的网站时无法完成OCSP检查,加载缓慢。

2020年11月20日,Let's Encrypt 推出了 R3 中间证书,使用了新的 OCSP 服务器地址(r3.o.lencr.org),问题得到解决。

如果仅仅是针对大陆的服务,之前,注意是之前最简单的方法是直用阿里云上可以申请到的免费 SSL 证书替换即可,问题立马解决。原因在于其使用的 OCSP 地址访问很通畅。于是我找了一个免费证书看了一下 OCSP 地址,并对比了一下 ping 值,发现如今 Let's Encrypt 的 OCSP 校验地址更快,是的,躺平就解决了:

ping Let's Encrypt OCSP URL
ping digi cert OCSP URL

更好的解决方案

采用躺平的方案固然可以,但是思考会发现,部分用户还是要经过这个校验过程,速度总会在资源加载时间的基础上再慢一些。于是乎 OCSP Stapling 出现了,这个翻译没那么明确,意义上是服务端先去查询 OCSP URL ,然后把结果在 SSL 握手的时候随证书一起发送到客户端,谓之 ”OCSP 装订”。客户端拿到这个信息就不用自己再去查询了,直接省去了一道网络交互,速度自然就快了。

经过实测,这一功能 Nginx 加一行 ssl_stapling 配置就能解决,如下例子:

ssl_certificate /path/to/your/fullchain.pem;
ssl_certificate_key /path/to/your/privkey.pem;
ssl_stapling on;

可能有读者会有疑问,服务端去请求不一样多了一道网络交互,只不过放在服务端了?是的,这个问题确实存在,但是好在这个查询有缓存,所以不是每次都会多这一道请求。按照 Nginx 文档的说法,默认会有一小时缓存,除非 OCSP Response Data 里面指定了不同的 Next Update 时间。我看了一下, Let's Encrypt 返回的结果,居然是一个星期有效期。

OCSP Response Data:
    OCSP Response Status: successful (0x0)
    Response Type: Basic OCSP Response
    Version: 1 (0x0)
    Responder Id: C = US, O = Let's Encrypt, CN = R3
    Produced At: Jun 16 20:30:00 2021 GMT
    Responses:
    Certificate ID:
      Hash Algorithm: sha1
      Issuer Name Hash: 48DAC9A0FB2BD32D4FF0DE68D2F567B735F9B3C4
      Issuer Key Hash: 142EB317B75856CBAE500940E61FAF9D8B14C2C6
      Serial Number: 041B19FDFD18149BC9753E14C9B7A95B7FDF
    Cert Status: good
    This Update: Jun 16 20:00:00 2021 GMT
    Next Update: Jun 23 20:00:00 2021 GMT

校验是否成功开启 OCSP Stapling

采用如下命令即可,如果成功会有如下反馈(当然,记得要替换域名):

$ openssl s_client -connect www.quarkay.com:443 -servername www.quarkay.com -status -tlsextdebug < /dev/null 2>&1 | grep -i "OCSP response"
OCSP response: 
OCSP Response Data:
    OCSP Response Status: successful (0x0)
    Response Type: Basic OCSP Response

如果要查看完整 OCSP 查询结果,去掉最后的 | grep ...... 部分即可,在执行后的一大坨结果中往上翻一翻就能看到。

OCSP 其实挺鸡肋的

这个问题乍一看会觉得,好像苹果的产品确实更安全哦?但其实问题并不这么单纯。首先这个机制会拖慢用户访问,其次有较大的泄漏隐私的风险,毕竟没人想被别人知道自己访问了什么网站,即使是 CA 这种机构。目的上看,也没对安全起到很大的作用,毕竟服务方连证书都泄漏了还能说啥。 Chrome 是默认关闭 OCSP 实时查询的,据网络资料说明,采用的是自己实现的一套认证机制。

仁者见仁,智者见智。

参考资料

https://datatracker.ietf.org/doc/rfc2560/
https://imququ.com/post/why-can-not-turn-on-ocsp-stapling.html
https://community.letsencrypt.org/t/ocsp-uri-r3-o-lencr-org/145920
https://letsencrypt.org/docs/integration-guide/
https://blog.cloudflare.com/ocsp-stapling-how-cloudflare-just-made-ssl-30/