旧版本 Linux 系统连接由“Let's Encrypt”颁发的证书的 https 网站,出现“证书不受信任、已过期”问题的最佳解决方案

最近需要在服务器里部署一些项目,系统环境是 Debian 9 x64,运行脚本后,无故终止。排除网络问题,查看报错,定位到是与某些必要组件的网站连接出现了错误。

报错为:

The certificate of 'www.xxx.xxx' is not trusted.
The certificate of 'www.xxx.xxx' has expired.

 

即使按网传方法,安装“ca-certificates”也无解。现将该问题复盘推演一遍,以便排查研究。

本次测试中,同时加入 Debian 10 与 Ubuntu 16.04.7 LTS(与 Debian 9 同代)这两个环境作为对照组测量。

测试情况

各测试系统环境,均是刚安装好系统时的初始状态,均已部署 wget curl ca-certificates openssl 等必备组件,测试时间:2021/10/05

各原版干净系统重装脚本是我编写的,链接如下,欢迎使用:

https://github.com/leitbogioro/Tools

 

Debian 9

preview

 

Debian 10

 

Ubuntu 16.04

 

wget/curl https://www.openssl.org 测试

Debian 9:证书不受信任、证书已过期

 

Debian 10:正常

 

Ubuntu 16.04:正常

https://www.openssl.org 使用的是由“Let's Encrypt”颁发的 TLS 证书,测试期间,根据该证书的有效时间表明,该证书未过期。

 

wget/curl https://letsencrypt.org 测试

Debian 9:证书不受信任、证书已过期

 

Debian 10:正常

 

Ubuntu 16.04:正常

https://letsencrypt.org 使用的是由“Let's Encrypt”颁发的 TLS 证书,测试期间,根据该证书的有效时间表明,该证书未过期。

 

wget/curl https://www.kernel.org 测试

Debian 9:证书不受信任、证书已过期

 

Debian 10:正常

 

Ubuntu 16.04:正常

https://www.kernel.org 使用的是由“Let's Encrypt”颁发的 TLS 证书,测试期间,根据该证书的有效时间表明,该证书未过期。

 

wget/curl https://github.com 测试

Debian 9:正常

 

Debian 10:正常

 

Ubuntu 16.04:正常

https://github.com 使用的是由“DigiCert, Inc.”颁发的 TLS 证书,测试期间,根据该证书的有效时间表明,该证书未过期。

 

wget/curl https://www.google.com 测试

Debian 9:正常

 

Debian 10:正常

 

Ubuntu 16.04:正常

https://www.google.com 使用的是由“Google Trust Services LLC”颁发的 TLS 证书,测试期间,根据该证书的有效时间表明,该证书未过期。

 

其他相关依赖状况

我查询了这三个实验环境中,与根证书公钥库存储、管理相关的“ca-certificates”组件,与 TLS 证书验证、连接相关的“OpenSSL”组件的版本号:

apt list --installed | grep -E "ca-certificates|openssl"

Debian 9:

ca-certificates:20200601(较旧)

openssl:1.1.0l(较新)

 

Debian 10:

ca-certificates:20200601(较旧)

openssl:1.1.1d(较新)

 

Ubuntu 16.04:

ca-certificates:20210119(较新)

openssl:1.0.2g(较旧)

Debian 9 的证书过期问题,如果是由官方源安装的证书库,OpenSSL 的版本过旧导致的,那么无法解释类似组合下,Debian 10 连接无问题;OpenSSL 版本更旧的 Ubuntu 16.04 也无问题。

 

测试结果总结

  • Debian 9 连接由“Let's Encrypt”签发证书作为 TLS 加密的 HTTPS 网站,均会出现失败;
  • Debian 9 连接由非“Let's Encrypt”签发证书作为 TLS 加密的 HTTPS 网站,暂无任何问题;
  • 不论使用 Debian 9 内置的何种工具,与使用了“Let's Encrypt”证书的网站连接,均会出现问题,所以推测该问题与下载工具无关;
  • 报错为“证书已过期”,但根据相关网站的证书有效期来看,结果与报错内容相悖;
  • TLS 证书有效性的验证,是由 OpenSSL 组件完成,版本越新,兼容性越好,Debian 9 和Debian 10 内置的 OpenSSL 大版本都比较新,为何只有 9 出了问题?为何内置的 OpenSSL 大版本更旧的 Ubuntu 16.04 反而没事?

有关证书验证日期失效这个问题,我在此做个简单科普。

一般来说,我们访问一个 HTTPS 网站,会用我们当前使用的操作系统中预先内置的,由各大权威根证书颁布机构颁发的,统一的公钥证书,跟网站的证书交换确认,然后再继续后面的加密过程。

频繁更换证书会为用户日常使用增添麻烦,但随着针对此证书建立的 HTTPS 连接,相关黑客攻击的强度增高,让证书一直有效也不是个好办法。所以为了在方便用户使用与增强安全性之间权衡,一般某个操作系统内置的公钥证书的有效期为 5~20 年之间不等,随着操作系统版本的更迭,更新版本的 OS 会内置更新的证书,且证书有效期限会有所延长。

反之,如果你使用旧 OS 上的浏览器,比如 Windows XP 上的 IE8,去访问现代 HTTPS 网站,很容易出现以下错误提示,即使点击“继续访问此网站”,也会存在潜在的安全风险:

这里有一份证书颁发机构“GlobalSign”提供的指南,指导使用Windows XP 与 Windows 2000 操作系统的用户,如何通过导入新的 GlobalSign 根证书,避免使用在这些平台上运行的浏览器,访问使用 GlobalSign 证书的 HTTPS 网站,出现证书错误提示。

可以看到,案例中演示的 Windows XP 系统,内置的由诸多机构颁发的根证书的有效期限,即使是最晚的一个时间戳(2020/07/06),也早已落后于现实时间(2021/10/05)。甚至可以说,如果你在 2021 年的今天,使用 Windows XP + 自带IE 组合,访问几乎所有的现代 HTTPS 网站,都会弹出错误提示。忽略错误继续访问,不安全;挨个将系统内置根证书替换成新的,工作量太大。所以对于普通桌面用户,及时更换新版本的操作系统和应用软件才是上策。

显然,在接下来的测试中,也验证了我的猜想,在 Debian 9 中,使用 wget 下载任意使用“Let’s Encrypt”证书的 HTTPS 网站的内容,只要添加“--no-check-certificate”,即使证书验证错误提示依旧存在,忽略掉错误也能正常下载:

对于我来说,有许多组件和工具是依赖于 Debian 9 上运行的,贸然更新到新系统,相关程序的兼容性、配置文件的改动都需要重新考虑和适配,成本太大。将使用的脚本中有关 wget 等命令前,全部添加类似“--no-check-certificate”作用的参数,修改工作量太大。这两种解决方案都不够完美。

所以,根据以上测试获得的经验,我们继续要做的,是排查 Debian 9 上,到底是哪个过期的根证书,导致的证书验证失效,只要定位到相关根证书,将其删除或替换,或许就能解决问题。

 

排查(一):了无收获

访问任意使用“Let's Encrypt”证书的网站,点击“查看证书”:

发现该证书的顶级机构的通用名称是“ISRG Root X1”,有效期至“2035/01/04”:

Debian 9 安装的 ca-certificates 版本是 20200601,Debian 10 安装的 ca-certificates 版本是 20210119,去 Debian 官网分别下载对应版本的软件包,解包看看它们分别内置的“ISRG Root X1”根证书是否有差异。

软件包:ca-certificates(20200601~deb9u2)

包下载链接:

软件包:ca-certificates(20210119)

包下载链接:

“ISRG Root X1”在两个 deb 包内所在路径下图所示:

用 NotePad ++ 分别打开两个证书,比较其中内容:

不能说完全一样,只能说毫无区别好嘛,这就费解了,看来问题并非“ISRG Root X1”根证书导致的,始作俑者是谁,我暂且蒙在鼓里。

 

排查(二):找中要害

管不管事儿,最后还得看 Google + 英文论坛,我的遭遇并非个例,在“ServerFault”论坛,找到了与此完全契合的讨论,并且网友在回答中,给出了问题发生的原因,与相对完美的解决方案。

提问者的描述比较简单,和我的环境、问题一致,不再详述。注意,该问题是 2021 年 10 月 1 日提出的,bug 出现的时间也从那时开始。

得票数第一的回答者抽丝剥茧,对该问题进行了 3 层描述,每一层描述逐步递进,最后直中要害,强烈推荐把该回答原文读一遍,并按照他的说明,在实际环境中做一下验证,这种感觉真的很精妙(奇怪的 high 点又增加了!)。

 

1. 正“新老交替”的 LE 证书链

他援引了“Let's Encrypt”官方论坛里给出的说明

Let’s Encrypt 颁发过两个根证书,分别是“DST Root CA X3”和“ISRG Root X1”,根证书“DST Root CA X3”的有效期限是 2021/09/29,已过期,“ISRG Root X1”的有效期限是 2024/09,截至本文成稿日(2021/10/05),还未过期。

 

2. OpenSSL 1.0 的兼容性问题

许多过旧的操作系统内,只内置了根证书“DST Root CA X3”,较新版本的操作系统内,同时内置旧根证书“DST Root CA X3”与新根证书“ISRG Root X1”,保留旧根证书是为了保持与旧操作系统的兼容性,内置新根证书是为了适应采用新的加密方式的现代 HTTPS 网站。目前对于搭载 Android 4.0 及以上操作系统版本、OpenSSL 版本 ≥ 1.1.X 的设备,访问新 HTTPS 网站或与旧设备之间通信,“如果旧的不行,就用新的验证”这个自动切换策略是没问题的。

问题就出在 OpenSSL 1.0.X,它会优先使用长度更短的“DST Root CA X3”与HTTPS网站做验证交换,一旦验证失效,就会报错终止。后续不再尝试用根证书“ISRG Root X1”做验证。OpenSSL 1.1.X 已修复该 Bug。

 

3. “libcurl3”坏了一锅汤

Debian 9 附带的“libcurl3”软件包中,有一个名为“libssl1.0.2”的共享库依赖,该依赖使 OpenSSL 强制以 1.0.2 版本运行。所以即使 Debian 9 内置了 OpenSSL 1.1.0l,它还是会重现上述第 2 点导致的问题。并且由于“libcurl3”是 Debian 9 默认源中“curl 7.52.1”的必要依赖,所以只要通过官方源安装 curl 组件,就会出现这个问题。

软件包:libcurl3(7.52.1-5+deb9u16)

Debian 9 官方源中的 curl 和其依赖 libcurl3 版本均为 7.52.1,而 libcurl3 就是导致 Debian 9 问题的万恶之源

我有一个猜想,如果卸载通过官方源安装的 curl 与 libcurl3,不安装,或自行编译安装更高版本的 curl,是否可以让 OpenSSL 以 1.1.0l 版本工作?尝试了一下,不行。我估计是卸载时 apt-get 提示与其相关的一堆依赖中,可能还有其他使 OpenSSL 只能以更低版本运行的组件,具体是哪个,没精力再做测试了,全卸了逐个用其他版本替换也很麻烦,难以实现。

早些年我就对 Linux 中,各种软件和组件依赖关系的错综复杂有所耳闻,今天从排查一个小 bug 入手,这种“摁下葫芦起了瓢”、“剪不断,理还乱”的感觉果然酸爽

软件包:libcurl4(7.74.0-1.3)

libcurl4 支持 OpenSSL 1.1.1,但仅兼容 Debian Buster(10)
Debian 10 官方源中的 curl 和其依赖 libcurl4 版本均为 7.64.0,比Debian 9 要新

实际上,AWS 在今年 10 月 1 日发布的一篇博客上,也指出 OpenSSL 1.0.2 的这个 bug 会导致相关系统出现该问题:

 

解决:Ubuntu 16.04

有细心的朋友应该已经发现了,案例中同为内置 OpenSSL 1.0.2X,libcurl3 的 Ubuntu 16.04.7,为何像穿了金钟罩一般,丝毫无事?

答案显而易见,早在 2021 年 5 月 19 日,就有用户反馈了证书届时失效造成的后果

在 2021 年 7 月 28 日后,Ubuntu 开发团队发布的“OpenSSL (1.0.2g-1ubuntu4.20) xenial-security”更新修复了该 bug,解决方法是在编译前的配置文件中,开启“X509_V_FLAG_TRUSTED_FIRST”。所以 Ubuntu 16.04 上的 OpenSSL 1.0.2g 不再受该 bug 影响,可以说是 Ubuntu 独享的 moment 了。

私以为该 bug 的紧迫性应该设为“高”,导致连接众多 HTTPS 站失效,挺操蛋的

注:有关“X509_V_FLAG_TRUSTED_FIRST”的作用,参见 OpenSSL 官方描述。开启此选项后,如果第一个证书链不被信任,OpenSSL 会尝试从证书库中,寻找其他在有效期内、可信任的证书替代验证, OpenSSL 1.1.X 版本此选项默认开启,无需再特别指定。

由于该选项必须在编译安装 OpenSSL 前,通过修改源码,在编译后生效,所以 Ubuntu 官方的解决办法,肯定是将重新编译好的二进制码上传到官方源中,如果你是在 2021 年 7 月 28 日之前安装的 Ubuntu 16.04 和 OpenSSL,该 bug 肯定会复现,通过官方源将 OpenSSL 组件更至最新,即可解决此问题。在此日期之后全新安装的 Ubuntu 16.04,也不会再碰到此问题。

apt-get update
apt-get install openssl -y

 

解决:其他受波及的 Linux 系统

鉴于我没有更多环境去实测,根据以上推论,我把该 Bug 可能波及到的 Linux 系统列举出来,具体还有哪些其他的发行版有问题,还得看你自己测试。如果你的系统出现相同问题,且不在以下列表,请在评论中告诉我,我可以添加到列表中。

Bug 触发条件:

以下条件满足其一即可:

1. 自带的,或通过系统官方源安装的 OpenSSL 版本为 1.0.X,当然 Debian 9 这个挂羊头卖狗肉,Ubuntu 16.04 这个修修补补还能用的俩奇葩早已超脱三界之外,查看 OpenSSL 版本命令如下:

openssl version

2. 系统未内置新的根证书“ISRG_Root_X1”(说明系统版本太旧),查询该证书是否内置的方法如下。

Debian/Ubuntu 输入:

dpkg-reconfigure ca-certificates

选择“yes”回车,翻页查找,如果该证书存在,按 Esc 退出:

CentOS,输入:

cat /etc/pki/ca-trust/extracted/openssl/ca-bundle.trust.crt | grep -E "ISRG_Root_X1"

如果有结果输出,说明已内置,反之则未内置。

3. AWS 文档或其他已存在的报告中提及的系统;

4. 最直观的方法就是查看本地连接到 LE 官网的报文,不报证书错误即没问题。

curl -I https://letsencrypt.org/

 

可能涉及到的 Linux 发行版:

  • CentOS 7 与 RHEL 7 及更旧版本;
  • Amazon Linux 和 Amazon Linux 2;
  • Ubuntu 14.04 及更旧版本;
  • Debian 8、Debian 9 等更旧版本;
  • Android 4.0 及更旧版本;
  • 任何符合以上“评判标准”条件其一,且官方源未发布针对 OpenSSL 1.0.X bug 修复的二进制编译文件的其他 Linux 衍生版本。

 

Debian 8/9 、Ubuntu 14.04 解决方法:

在证书配置文件中,删除“DST_Root_CA_X3”证书,并重载根证书配置

sed -i '/^mozilla\/DST_Root_CA_X3/s/^/!/' /etc/ca-certificates.conf && update-ca-certificates -f

警告,此操作会使系统失去与仅安装了“DST_Root_CA_X3”证书的旧设备的兼容性,请谨慎操作。

 

CentOS 6/7 解决方法:

删除系统内置的,受信任的根证书目录中的“DST_Root_CA_X3”证书

rm -rf /etc/ca-certificates/trust-source/DST_Root_CA_X3.pem

更新证书信任列表配置

update-ca-trust

警告,此操作会使系统失去与仅安装了“DST_Root_CA_X3”证书的旧设备的兼容性,请谨慎操作。

 

其他 Linux 发行版

核心思路就是:1. 删除系统内置根证书信任区,或证书管理器配置文件中的“DST_Root_CA_X3”证书,2. 重载证书管理器配置。后果同样为失去兼容旧系统,具体命令和方法请自行探究。

 

更旧的系统

低于 Ubuntu 14.04、CentOS 6 版本的操作系统,可能仅内置了“DST_Root_CA_X3”且并未内置“ISRG_Root_X1”证书,这些旧版本操作系统的生命周期支持已停止,继续使用,还会面临其他严重的兼容性问题与安全问题,即使可以通过手动将新证书内置到系统,删除旧证书的方式与采用 LET 证书的现代 HTTPS 网站兼容,但也不建议继续使用。有空我再出一个新增证书的教程吧。

 

总结

Let's Encrypt 是一个偏好采用激进新技术的 TLS 证书颁发机构,无论是在业界首创的免费证书签发、续签模式,还是较短的根证书有效期、网站证书有效期,以及新证书标准的应用,这些举措都推动了 HTTPS 技术、网络安全的进步和发展。

本文所涉及的问题,是围绕 LET 新旧根证书的过渡期中,旧证书的失效,与旧版本 OpenSSL 的 bug 所展开的。单纯的解决这个问题,只是一两行命令的事,但通过实验测试问题、总结问题的诱因、并对一些特殊案例做出合理解释,是不容易的事。通过实践培养科学的思维,有助于触类旁通,届时面临其他难题也能游刃有余。

将服务端环境、软件维持在旧版本,显然是每个运维“梦寐以求”的,因为相比新技术带来的性能、稳定性、安全性、易用性的提升,无需加班,免受环境更换后繁琐的重新部署、兼容性测试等更加诱人,毕竟待在舒适区是人类的天性,如何权衡“守旧”与“逐新”,是每个运维、开发等技术人员不得不面临的终极抉择。

本站文章资源均来源自网络,除非特别声明,否则均不代表站方观点,并仅供查阅,不作为任何参考依据!
如有侵权请及时跟我们联系,本站将及时删除!
如遇版权问题,请查看 本站版权声明
THE END
分享
二维码
海报
旧版本 Linux 系统连接由“Let's Encrypt”颁发的证书的 https 网站,出现“证书不受信任、已过期”问题的最佳解决方案
最近需要在服务器里部署一些项目,系统环境是 Debian 9 x64,运行脚本后,无故终止。排除网络问题,查看报错,定位到是与某些必要组件的网站连接出现了错误。……
<<上一篇
下一篇>>
文章目录
关闭
目 录