Let's Encrypt 出现证书不受信任已过期的解决方案 发表于 2021-10-08 | 分类于 Linux | 暂无评论 ### 报错提示: 最近需要在服务器里部署一些项目,系统环境是 Debian 9 x64,运行脚本后,无故终止。 排除网络问题,查看报错,定位到是与某些必要组件的网站连接出现了错误。 报错为: The certificate of 'www.xxx.xxx' is not trusted. The certificate of 'www.xxx.xxx' has expired. 即使按网传方法,安装“ca-certificates”也无解。 ### 测试: 各测试系统环境,均是刚安装好系统时的初始状态,均已部署 wget curl ca-certificates openssl 等必备组件,测试时间:2021/10/05 wget/curl https://www.openssl.org 测试 Debian 9:证书不受信任、证书已过期 Debian 10:正常 Ubuntu 16.04:正常 https://www.openssl.org 使用的是由“Let's Encrypt”颁发的 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 网站,暂无任何问题; ### TLS 证书有效性的验证 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 网站,出现证书错误提示。 指南:https://support.globalsign.com/ca-certificates/root-certificates/update-globalsign-root-certificate-windows-xp-windows-2000 可以看到,案例中演示的 Windows XP 系统,内置的由诸多机构颁发的根证书的有效期限,即使是最晚的一个时间戳(2020/07/06),也早已落后于现实时间(2021/10/05)。甚至可以说,如果你在 2021 年的今天,使用 Windows XP + 自带IE 组合,访问几乎所有的现代 HTTPS 网站,都会弹出错误提示。忽略错误继续访问,不安全;挨个将系统内置根证书替换成新的,工作量太大。所以对于普通桌面用户,及时更换新版本的操作系统和应用软件才是上策。 显然,在接下来的测试中,也验证了我的猜想,在 Debian 9 中,使用 wget 下载任意使用“Let’s Encrypt”证书的 HTTPS 网站的内容,只要添加“--no-check-certificate”,即使证书验证错误提示依旧存在,忽略掉错误也能正常下载 ### ServerFault 在“ServerFault”论坛,找到了与此完全契合的讨论,并且网友在回答中,给出了问题发生的原因,与相对完美的解决方案。 ServerFault:https://serverfault.com/questions/1079199/client-on-debian-9-erroneously-reports-expired-certificate-for-letsencrypt-issue/1079205#1079205 #### 正“新老交替”的 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),还未过期。 #### 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。 #### “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 组件,就会出现这个问题。 ### 解决: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 了。 #### X509_V_FLAG_TRUSTED_FIRST 注:有关“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 触发条件: 以下条件满足其一即可: 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. 重载证书管理器配置。后果同样为失去兼容旧系统,具体命令和方法请自行探究。 ### win7 访问好多网站提示证书错误进不去 let的证书链到期, win7 和 2008 如果没有自动更新。 需要手动导入 https://letsencrypt.org/certificates/#root-certificates Root Certificates--Active--Self-signed--der 下载后,双击 der 文件就可以 转载修改自 >https://zhuanlan.zhihu.com/p/417627543