目录
引子
一直以来,我都是使用 Caddy 来部署自己的一些网站,这是一个用 golang 写的 web 服务端,类似 nginx,但一个显著的优势是默认支持 HTTPS,且无需额外配置。
下文摘抄自维基百科:
Caddy 默认通过检查域名来启用 HTTPS (通过 ACME protocol 检查域名并签发证书), 并且重定向 HTTP 请求到 HTTPS。它在启动期间根据需要签发证书,并在服务器的使用期间自动重签发。 Let’s Encrypt 是默认的证书颁发机构,……。在 2016 年第一季度,有百分之二的 Let’s Encrypt 证书是由 Caddy 签发的。
可见,Caddy 和 Let’s Encrypt 的关系甚是紧密。
其实我的博客本质上就是一个静态网站,使不使用 HTTPS 原本区别不大。但是当我看到自己的网站上出现了不是自己挂载的广告内容时,我才对“运营商劫持”这件事有了更清醒的认识,于是带着愤怒,借助 Caddy 实现了全站 HTTPS,在它的保驾护航下,一直运转至今。
前几天,我在做一些维护工作时,发现 Caddy 一直启动不起来,一直卡在 Activating privacy features...
这一步,在重试了几次之后,我发现了规律,不是启动不起来,而是启动耗时很长,等上几分钟后还是能正常启动的,这时候查看日志,可以看到多条类似这样的日志:
[WARNING] Stapling OCSP: no OCSP stapling for [blog.wolfogre.com]: making OCSP request: Post "http://ocsp.int-x3.letsencrypt.org": dial tcp 69.63.176.15:80: i/o timeout
原来 Caddy 会在正式工作之前,为每个域名向 http://ocsp.int-x3.letsencrypt.org
发起校验请求,然而每次都会连接失败,且超时时间目测是 30 秒。因为是串行执行,这就需要你等上 N 个 30 秒了。不过好在,即使校验失败,Caddy 也不会放弃运行,所以在等待足够久之后,还是可以正常工作的。
我满腹狐疑,尝试在服务器上 curl
、ping
这个 ocsp.int-x3.letsencrypt.org
地址,发现确实是连不通的。因为日常运行时,Caddy 也会不定时向这个地址发起请求,所以我搜索了一下日志,发现大约是从 4 月 1 日 10 时开始,这样的错误日志大量出现,一直至今。
2020/04/01 09:50:56 [ERROR] Checking OCSP: no OCSP stapling for [image.wolfogre.com]: making OCSP request: Post http://ocsp.int-x3.letsencrypt.org: dial tcp 64.13.192.74:80: connect: connection refused
2020/04/01 09:51:26 [ERROR] Checking OCSP: no OCSP stapling for [blog.wolfogre.com]: making OCSP request: Post http://ocsp.int-x3.letsencrypt.org: dial tcp 66.220.147.11:80: i/o timeout
2020/04/01 10:51:25 [ERROR] Checking OCSP: no OCSP stapling for [image.wolfogre.com]: making OCSP request: Post http://ocsp.int-x3.letsencrypt.org: dial tcp 31.13.64.1:80: i/o timeout
2020/04/01 10:51:55 [ERROR] Checking OCSP: no OCSP stapling for [blog.wolfogre.com]: making OCSP request: Post http://ocsp.int-x3.letsencrypt.org: dial tcp 174.37.54.20:80: i/o timeout
2020/04/01 11:51:25 [ERROR] Checking OCSP: no OCSP stapling for [blog.wolfogre.com]: making OCSP request: Post http://ocsp.int-x3.letsencrypt.org: dial tcp 88.191.253.157:80: i/o timeout
2020/04/01 11:51:55 [ERROR] Checking OCSP: no OCSP stapling for [image.wolfogre.com]: making OCSP request: Post http://ocsp.int-x3.letsencrypt.org: dial tcp 31.13.74.17:80: i/o timeout
2020/04/01 12:51:25 [ERROR] Checking OCSP: no OCSP stapling for [image.wolfogre.com]: making OCSP request: Post http://ocsp.int-x3.letsencrypt.org: dial tcp 31.13.75.18:80: i/o timeout
2020/04/01 12:51:55 [ERROR] Checking OCSP: no OCSP stapling for [blog.wolfogre.com]: making OCSP request: Post http://ocsp.int-x3.letsencrypt.org: dial tcp 31.13.75.17:80: i/o timeout
……
“4 月 1 日 10 时开始”?这个时间点未免也太巧合了,让我嗅出了一丝人为的味道……
深究
我尝试在在网上搜索了一下,已经有人发现了这个问题,核心点就是 ocsp.int-x3.letsencrypt.org
无法访问,利用 Let’s Encrypt 签发证书可能受阻。
- 4 月 2 日,V2EX,国内 Let’s Encrypt 的 OSCP 域名 ocsp.int-x3.letsencrypt.org 的解析被污染了?
- 4 月 4 日,蓝点网,Let’s Encrypty免费证书用户请注意:你的证书可能已经无法签发/更新
- 4 月 6 日,Let’s Encrypty 社区论坛,ocsp.int-x3.letsencrypt.org is not working in China
我倒吸了一口凉气,如果不能使用 Let’s Encrypt 签发 HTTPS 证书,像我这样不舍得掏钱买付费证书的人,难不成就得回到 HTTP 时代,任由网络运营商的劫持广告肆虐?
帖子中,大家开始了各种关于这件事的阴谋论揣测,其中的一些分析也不乏一些道理,但是我还是很难相信会有这样强硬且无理的举措,让 Let’s Encrypt 在中国境内一夜猝死?
我重新梳理了一遍 Let’s Encrypt 的工作逻辑,稍稍放了点心,结论是:ocsp.int-x3.letsencrypt.org
域名被封,其实并不会对使用 Let’s Encrypt 有较大影响,仍然是可以继续签发、更新的。
根据 Let’s Encrypt 对其工作原理的介绍,我们可以看到,签发证书时,主机确实需要连接至 Let’s Encrypt,发起一次证书签名请求(CSR):
但需要注意的是,这个过程并不需要 ocsp.int-x3.letsencrypt.org
这个域名参与,换句话说,即使这个域名被封,也不影响上述签发证书的过程。我已经实操验证过了,签发、更新证书确实是可以正常进行的。
被影响到的其实是证书被吊销过程:
当想吊销证书时,主机会发起一个吊销请求,Let’s Encrypt 将吊销信息发布到正常的吊销通道(即 OCSP)中,以便浏览器等依赖方知道他们不应该接受这个已被吊销的证书。而 ocsp.int-x3.letsencrypt.org
这个域名,正是为浏览器等依赖方提供查询证书吊销状态的服务,即 OCSP Server。
所以这样看来,Caddy 启动时向 OCSP Server 发起请求,目的就是检查机器上缓存的证书是否已经被吊销,而如果请求受阻,无法确认证书吊销状态,Caddy 是默认证书有效的,所以仍可以继续工作。换句话说,屏蔽 ocsp.int-x3.letsencrypt.org
并非会让 Let’s Encrypt 完全无法使用,但这一手段大大削弱了其安全性。可以想象,当证书泄露时,即使已经成功吊销了被泄露的证书,但因为浏览器无法访问 OCSP Server,也就无法确认证书状态,导致可能继续信任被泄露的证书,访问到恶意站点。
多损啊。
结论
话说回来,当浏览器无法确定一个证书是否已经被吊销,这个时候浏览器是信任这个证书,还是不信任这个证书呢?
在文章《你不在意的 HTTPS 证书吊销机制》里,作者详细展开了在吊销证书这件事情上会面临的种种难题,其中“OCSP Server 无法访问”这一情况,本身就是这套证书吊销机制的核心痛点,所以各家厂商的浏览器在对待 OCSP 这一机制时,明显是偏保守的,鲜有说“无法请求 OCSP Server 进行校验就认定证书不安全”,这样过分依赖 OCSP Server 可用性的做法。
其中更有甚者,早早就弃用了 OCSP,认为它效率低、速度慢,并一针见血地提到:“攻击者既然能拦截 HTTPS 请求,就同样能阻断 OCSP 请求,从而规避这一检查机制。”——我相信你已经猜到了,这家浏览器就是 Google Chrome,见《Google Chrome Will No Longer Check for Revoked SSL Certificates Online》。
到这里,我可以说,我可以暂时放心了,除了每次重启 Caddy 时需要等上一会儿,也没什么其他影响。
但是,然而,but,however,以上结论都需要加一个时间限定词,就是“到目前为止”。
这次故障过于诡异,我很难说他到底是一个“缺陷”,还是一个“特性”,如果是“缺陷”自然会有人将其修复,如果是“特性”自然又人会进一步加强这方面的“特性”。
我实在想不通,这样做的意义是什么,是为了释放一个信号?让我意识到在国内使用 Let’s Encrypt 是有风险的,进而转向付费证书,或其他没有被封风险的免费证书?
我不敢妄言。
我无 fuck 说。
后记
5 月 1 日,刚好一个月后,错误日志戛然而止:
2020/05/01 14:13:20 [WARNING] Stapling OCSP: no OCSP stapling for [blog.wolfogre.com]: making OCSP request: Post "http://ocsp.int-x3.letsencrypt.org": dial tcp 69.171.233.24:80: i/o timeout
2020/05/01 14:13:50 [WARNING] Stapling OCSP: no OCSP stapling for [image.wolfogre.com]: making OCSP request: Post "http://ocsp.int-x3.letsencrypt.org": dial tcp 69.171.233.24:80: i/o timeout
2020/05/01 15:01:13 [WARNING] Stapling OCSP: no OCSP stapling for [blog.wolfogre.com]: making OCSP request: Post "http://ocsp.int-x3.letsencrypt.org": dial tcp 69.63.180.173:80: i/o timeout
2020/05/01 15:01:43 [WARNING] Stapling OCSP: no OCSP stapling for [image.wolfogre.com]: making OCSP request: Post "http://ocsp.int-x3.letsencrypt.org": dial tcp 69.63.180.173:80: i/o timeout
2020/05/01 16:06:50 [INFO][cache:0xc000081b30] Scanning for stale OCSP staples
2020/05/01 16:06:50 [INFO][cache:0xc000081b30] Done checking OCSP staples
2020/05/01 17:06:50 [INFO][cache:0xc000081b30] Scanning for stale OCSP staples
2020/05/01 17:06:50 [INFO][cache:0xc000081b30] Done checking OCSP staples
2020/05/01 18:06:50 [INFO][cache:0xc000081b30] Scanning for stale OCSP staples
现在 ping ocsp.int-x3.letsencrypt.org
已经没有问题了:
$ ping ocsp.int-x3.letsencrypt.org
PING ocsp.int-x3.letsencrypt.org (96.17.68.81) 56(84) bytes of data.
64 bytes from ocsp.int-x3.letsencrypt.org (96.17.68.81): icmp_seq=1 ttl=48 time=234 ms
64 bytes from ocsp.int-x3.letsencrypt.org (96.17.68.81): icmp_seq=2 ttl=48 time=234 ms
64 bytes from ocsp.int-x3.letsencrypt.org (96.17.68.81): icmp_seq=3 ttl=48 time=234 ms
64 bytes from ocsp.int-x3.letsencrypt.org (96.17.68.81): icmp_seq=4 ttl=48 time=235 ms
^C
--- ocsp.int-x3.letsencrypt.org ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 234.277/234.852/235.396/0.713 ms
$ curl -v ocsp.int-x3.letsencrypt.org
* About to connect() to ocsp.int-x3.letsencrypt.org port 80 (#0)
* Trying 96.17.68.81...
* Connected to ocsp.int-x3.letsencrypt.org (96.17.68.81) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: ocsp.int-x3.letsencrypt.org
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx
< Content-Length: 0
< Cache-Control: max-age=5425
< Expires: Sat, 09 May 2020 09:38:02 GMT
< Date: Sat, 09 May 2020 08:07:37 GMT
< Connection: keep-alive
<
* Connection #0 to host ocsp.int-x3.letsencrypt.org left intact
此前所有的阴谋论貌似都被打脸了。
不管怎样,无论是意外事故还是人为引起,但愿不要再发生了。
评论加载中……
若长时间无法加载,请刷新页面重试,或直接访问。