eMudhra 证书:攻击者需要什么,哪些控制措施能阻止攻击
eMudhra 的密钥可以用来伪造证书,但每种攻击还需要其他条件:五种攻击途径以及如何阻断。
本文仅用于教育目的,不能替代正式的智能合约审计、法律建议、金融建议或针对具体协议的安全审查。
eMudhra 的八个中间 CA(六个用于 TLS,两个用于代码签名)的私钥,可以从证书本身推算出来。用其中六个 TLS 中间 CA,任何人都可以为任意域名签发证书,而没有更新的客户端会把它当作有效证书接受。用两个代码签名中间 CA,曾经可以给软件签名,并让 Windows 把它当作已签名的软件接受。仅凭这些还不足以拦截流量:攻击者还必须处在连接的中间位置。
一个被攻破的 CA 或中间 CA,本身并不能带来流量拦截或远程代码执行。要拦截流量,攻击者还必须控制网络路径、DNS、代理或下载软件包的来源,同时客户端仍然信任受影响的证书链。更新根证书或拦截这些中间 CA,就能消除这种信任。哈希、签名和范围检查可以阻止对软件包和数据的篡改,但无法阻止令牌或流量被读取。

攻击需要的条件
要用这些密钥拦截或篡改一个连接,必须同时满足两个条件:
- 客户端仍然信任受影响的证书链,并且不要求 Certificate Transparency(CT)。
- 攻击者控制客户端与服务器之间路径上的某个点:网络、DNS 解析、代理或软件包分发点。
这就足以读取令牌或请求。要塞进被篡改的软件包或数据,还需要第三个条件:没有其他控制措施能发现这一改动,例如固定的哈希、针对数据的签名或范围检查。
第一个条件有一个细节。六个 TLS 中间 CA 挂在 emSign Root TLS CA - G3 之下,两个代码签名中间 CA 挂在 emSign Root CS CA - G3 之下;这两者都位于 emSign ECC Root CA - G3 之下,也就是出现在信任库中的那个根证书。此外,每个中间 CA 都有来自 AAA Certificate Services(Sectigo 的一个根证书)的交叉签名。如果信任库仍然接受 AAA 用于 TLS,只删除 emSign ECC Root CA - G3 是不够的,未修复的 OpenJDK cacerts 和旧版本的 certifi 就是这种情况。能同时切断两条路径的是更新,因为已修复的版本会拦截这些中间 CA。
Cloudflare 是这样描述的:由于密钥强度不足,攻击者可以为任意域名生成伪造证书,用它冒充服务器,拦截或修改流量。这就是所有中间人攻击的原理。区别在于,伪造的证书能通过未更新客户端的验证。
Google 和 Mozilla 的 Dennis Jackson 都指出,CT 日志中没有这些中间 CA 签发的证书,因此要求 CT 的浏览器不可能被攻击。风险在于不要求 CT 的客户端:curl、各语言的运行时、pip、uv 和容器镜像。Docker 在 10 月 22 日发布的 Docker Desktop 4.96.3 版本说明中,就其 CLI 和 daemon 说明了这一点:能够访问网络的攻击者可能利用这些证书拦截它们的 TLS 连接。
据该 CA 自己说明,这些中间 CA 创建于 2025 年 4 月 30 日,八个中有七个从未在生产环境中使用,唯一使用过的那个没有签发任何证书。Jackson 写道,目前不清楚是否有人利用这一缺陷攻击了不要求 CT 的客户端。没有公开的滥用证据,但从外部也无法排除。因此,有必要检查哪些流量经过了这些客户端。

攻击途径 A:冒充外部 API
用这些密钥可以为任意域名伪造有效的 TLS 证书,但只有在攻击者同时控制网络路径(Wi-Fi、代理、DNS 或 BGP),且客户端仍然信任该证书链、不要求 Certificate Transparency 时,才能用来拦截。Chrome、Firefox、Edge 和 Safari 已经拦截这些中间 CA,并要求 CT。
一个后端、一个 CI job 或一个 agent 通过 HTTPS 调用外部 API,请求头里带着令牌。如果攻击者控制了一个拦截点,而客户端接受了伪造的证书链,这次调用就会到达攻击者而不是服务提供方。攻击者可以读取令牌、请求和响应,也可以修改它们。
在这里,哈希帮不上忙:只要令牌经过被拦截的连接,攻击者就能读到。能切断这一攻击途径的是客户端上最新的根证书或已拦截的中间 CA、pinning 或 mTLS。
攻击途径 B:通过 HTTPS 下载的制品
如果攻击者能拦截一次 HTTPS 下载(按 tag 的 docker pull、pip、npm 或 curl | sh),就可以提供一个被篡改的制品,但前提是没有任何机制通过其他途径验证其完整性。固定的镜像 digest、npm lockfile 的 integrity、pip --require-hashes、用 cosign/Sigstore 验证,或用 GPG 签名的 apt/rpm 软件源,都能发现这一改动。
在构建或部署过程中,会下载镜像、软件包和脚本。如果攻击者控制了分发点,而客户端接受了伪造的证书链,被替换的制品就会在构建或生产环境中运行,并能读取它能接触到的 secret。每种下载方式都有自己的防御手段,或者没有:
- “docker pull image:tag”通过被拦截的通道解析 tag。“image@sha256:…”按内容寻址。
- npm 会针对 lockfile 中已经固定的内容检查 integrity,但不保护首次解析,也不保护对新软件包执行的“npm install”。
- 除非要求哈希,pip 和 uv 会安装收到的任何内容。
- “curl | sh”完全没有防御:收到什么就执行什么。
- apt 和 rpm 用机器上已有的密钥验证 GPG 签名的元数据,即使下载不走 TLS。
在 Python 中,有一个细节会改变处理顺序。Christian Heimes 在 Python Discourse 关于这一事件的讨论帖中解释说,pip 除了加载系统的根证书外,总会加载其内置 certifi 的根证书,而且没有受支持的方法可以关闭这一点。只更新系统是不够的:必须更新 pip。
攻击途径 C:驱动决策的数据
一个服务通过 HTTPS 查询价格、余额或风险参数,并据此自动做出决策。如果路径上的攻击者用伪造证书冒充数据提供方,就可以返回被篡改的数据。客户端通过一个看起来有效的通道收到这些数据,错误最终会体现在抵押品、清算、估值或平仓的决策中。
在这里,TLS 只是其中一层。即使通道失效仍然有效的控制措施,在数据本身:
- 签名数据源:提供方对数据签名,客户端用事先知道的密钥验证签名,与服务器证书无关。
- 独立来源:从多个提供方或预言机获取同一数据进行比较,不一致时不采取行动。
- 限值:拒绝超出预期范围的值,或与上一个被接受的值相比变化过大的值。
- 新鲜度:要求带时间戳,丢弃过期或重复的数据。
- 客户端上的根证书保持更新,与攻击途径 A 和 B 相同。
当其中任何一项检查失败时,稳妥的做法是暂停自动化,把决策交给人,而不是依据可疑的数据采取行动。
攻击途径 D:Windows 上的代码签名
八个中间 CA 中有两个(EM OV CS CA - G3B 和 G3C)是代码签名 CA(EKU codeSigning),并链接到 Windows 信任用于 Code Signing 的根证书(emSign Root CS CA - G3 和 AAA Certificate Services):用它们的密钥,曾经可以给软件签名,并让 Windows 认为签名有效,直到 Microsoft 在 2026 年 10 月 20 日拦截了它们。
Mozilla 的事件报告(Bugzilla 2083449)是这样说的:其中六个证书用于 TLS,另外两个用于代码签名,并受到 Microsoft 的信任。这一攻击途径不需要处在网络路径上,但也不会带来远程执行:必须有人下载并运行这个已签名的二进制文件。目前没有用这些中间 CA 签名的二进制文件的公开记录。
攻击途径 E:签名负载和客户端证书

利用六个 TLS 中间 CA 的密钥,攻击者可以给自己签发一张任意名称的新证书,用它对篡改过的负载签名,或在 mTLS 中把它作为客户端证书出示。只有这样的后端才会接受:只要签名或客户端证书能链接到公共根证书库(certifi、系统信任库或 Java 的 cacerts)就认可,而没有固定它所期望的密钥、证书或 CA。最常见的负载签名方式(HMAC、固定的公钥、按“kid”查找的 JWKS 或私有 CA)不受影响。
攻击者得不到任何合法签名者的密钥或证书,已有的签名也依然有效。攻击者得到的是一张自己的证书,对于只检查证书链能否到达公共根证书的验证方来说,它会被当作有效证书。检查证书名称也起不到保护作用,因为名称是攻击者随意填写的。
可能发生这种情况的场景是具体的:
- 在 x5c 头中携带自身证书、并依据公共信任库进行验证的 JWS 或 JWT 令牌。RFC 7515 要求验证证书链,但这并不能说明是谁签的名:密钥必须来自能够认证其来源的渠道。
- 用 signxml 在不带参数的情况下验证的 XML 签名(SAML、WS-Security)。其文档提醒,在这种情况下,它会信任任何由系统 CA 信任库所接受的证书做出的签名。
- 接受任何公共 CA 签发的客户端证书、并按名称授权的 mTLS 服务器。六个 TLS 中间 CA 都可以签发客户端证书。
Python 默认不会信任这些证书来验证签名:标准库不验证负载签名,而在 cryptography 中必须显式构建信任库和验证器。此外,篡改后的负载必须送达后端:要么该 endpoint 接受任何有效签名者的直接提交,要么攻击者处在路径上,就像攻击途径 A 那样。
它们不能带来的:远程代码执行
它们不能直接带来远程代码执行:伪造的证书只能用来冒充 TLS 服务器,攻击者的代码只有在受害者安装并运行被篡改的制品(攻击途径 B),或客户端另有其他漏洞时才会被执行。
Mozilla、Google 和 Cloudflare 在各自的公告中都没有描述代码执行:它们谈的是冒充服务器以及拦截或修改流量。
如何防护
macOS 上每个工具的详细步骤,见文末链接的修复文章。这里给出每个攻击途径的最低要求,所列命令都已在 Linux 上原样运行过。
针对攻击途径 A:信任库
第一步是弄清楚你用的是哪些版本。在 Debian 或 Ubuntu 的机器或镜像中:
node --version
python3 -m pip list 2>/dev/null | grep -iE '^(pip|certifi|uv) '
dpkg -s ca-certificates | grep '^Version'一手来源给出的最低版本:
- Node:根据分支,24.22.1、22.23.4 或 26.12.1(Node 10 月 21 日的漏洞公告)。
- certifi 2026.10.19、pip 26.2.2 和 uv 0.13.4(Seth Larson 在 Python Discourse 上的通知)。
- ca-certificates:你的发行版发布的包含此更改的版本。在此之前,Jackson 的页面给出了一个不再信任受影响根证书的操作步骤,并提醒这不适合普通用户。
- Docker Desktop 4.96.3 或更高版本。其版本说明称,它取消了对这些证书的信任。
此外,下面这个 grep 可以在代码仓库中找出 Python、Node、Go 和 curl 中常见的关闭验证的写法。遇到证书错误时,关闭验证从来都不是解决办法:不做验证的客户端会接受任何证书,而不只是这些中间 CA 签发的证书。
grep -rnE --exclude-dir={.git,node_modules,.venv} \
'verify *= *False|CERT_NONE|rejectUnauthorized: *false|NODE_TLS_REJECT_UNAUTHORIZED|InsecureSkipVerify: *true|curl +(-k|--insecure)' .每一处匹配都需要逐一查看:有些会出现在测试或本地工具中。真正要紧的,是调用外部 API 的代码中的那些。
还有两项措施可以减少可能的损失。把每个服务的出站网络限制在它所需要的目标上,可被拦截的连接就更少。而轮换那些曾从未更新的客户端、经由你不控制的网络传输过的令牌,可以追溯性地关闭此前的暴露窗口。
Java,最复杂的情况
未更新的 JDK 不会拦截 eMudhra 的证书:它通过 emSign ECC Root CA - G3 和 AAA Certificate Services 的交叉签名信任这些中间 CA。而且,很容易以为一切都已更新,其实并没有。OpenJDK 10 月 21 日的公告(CVE-2026-91403)解释了原因:
- 单独安装、以归档文件形式下载的 OpenJDK 运行时,自带信任库,很可能包含被攻破的证书。必须更新它。
- Arch Linux、Debian、Devuan、Fedora、Gentoo、Oracle Linux、Red Hat Enterprise Linux 和 Ubuntu 的 OpenJDK 软件包使用操作系统的证书;在这些系统上,更新系统证书就够了。FreeBSD 和 Homebrew 的则必须直接更新。
- 如果装了不止一个运行时,每一个都要重复这一步。
- 带 Java 的容器镜像有自己的 JRE 和信任库。更新宿主机不会改变它们:必须用已修复的 JDK 重新构建。
这一修复在 OpenJDK 中编号为 JDK-8395142,在 Oracle 中为 JDK-8395555,它并不删除根证书:而是把八个中间 CA 及其八个 AAA 交叉签名加入 JDK 的已拦截证书列表。这个列表就是 lib/security 中的 blocked.certs 文件,在 Java 8 中是 blacklisted.certs。emSign ECC Root CA - G3 和 AAA Certificate Services 仍然保留在 OpenJDK 的 cacerts 中。因此,只删除前者是不够的,而删除 AAA 并不推荐:这可能会中断与仍然链接到该根证书的服务的连接,Jackson 也提醒,不再信任它不适合普通用户。
10 月 21 日之前的 JDK 不会拦截这些中间 CA。请更新到已修复的版本;如果无法更新,就用 Oracle 在 https://ops.java/emudhra 发布的文件替换 lib/security/blocked.certs(Java 8 中为 blacklisted.certs),并重启 Java 应用。
根据版本说明或在二进制文件中核实,已经包含拦截的版本:
- Oracle JDK 27.0.1.0.2、25.0.5.0.2、21.0.13.0.2、17.0.21.0.2、11.0.33.0.2 和 8u511 b32(1.8.0_511-b32),于 10 月 21 日发布。OpenJDK 在 jdk.java.net 上发布了 27.0.1.0.2。
- Amazon Corretto 25.0.5.0.9、21.0.13.0.10 和 8.512.08.1。
- Homebrew 当前的 openjdk、openjdk@21 和 openjdk@17 formula。
截至 10 月 23 日尚无修复的:Homebrew openjdk@11 和 openjdk@8、Azul Zulu、Red Hat Enterprise Linux 的 OpenJDK 软件包,以及 Temurin 8 和 11。在 Oracle JDK 8 上,10 月 20 日发布的 8u511(1.8.0_511-b09)仍然受影响:如果“java -version”的输出中没有“b32”,请更新。Debian 和 Ubuntu 的 Java 8 没有经过核实的已修复版本。Temurin 21 和 25 没有包含拦截,但也没有附带 emSign ECC Root CA - G3 和 AAA Certificate Services,因此会拒绝这条证书链。
ops.java 是 Oracle 为这份公告使用的官方域名,但在 10 月 23 日它返回 403 错误,所以最好不要只依赖它:更新仍然是主要途径。文末链接的 macOS 修复文章给出了详细步骤:下载、一个检查文件格式、保留原有条目并保存副本的脚本,以及用 jshell 进行验证。用 keytool -delete 删除根证书不是主要途径。
要知道该查哪里,下面这条命令会列出 Linux 机器或容器中单独安装的运行时的信任库:
find / -type f -name cacerts -path '*/lib/security/*' 2>/dev/null对每一个信任库,下面这条命令会告诉你它的 cacerts 是否包含这两个根证书中的任何一个。它按 SHA-256 指纹查找,指纹取自 Jackson 发布的列表,因为别名会随构建 JDK 的一方而变化。把 JAVA_HOME 设为你正在检查的 JDK 所在的目录:
"$JAVA_HOME/bin/keytool" -list -v -cacerts -storepass changeit \
| awk '/^Alias name:/ {alias=$0}
/SHA256: 86:A1:EC:BA:08:9C:4A:8D:3B:BE:27:34:C6:12:BA:34:1D:81:3E:04:3C:F9:E8:A8:62:CD:5C:57:A3:6B:BE:6B/ {print alias, "-> emSign ECC Root CA - G3"}
/SHA256: D7:A7:A0:FB:5D:7E:27:31:D7:71:E9:48:4E:BC:DE:F7:1D:5F:0C:3E:0A:29:48:78:2B:C8:3E:E0:EA:69:9E:F4/ {print alias, "-> AAA Certificate Services"}'下面这条命令统计 blocked.certs 中有多少个来自同一列表的 16 个指纹。文件的第一行必须是“Algorithm=SHA-256”,计数必须是 16;数字更小说明拦截不存在或不完整。它也可以用来在安装前检查下载或复制来的 blocked.certs。在 Java 8 中,路径是 "$JAVA_HOME/jre/lib/security/blacklisted.certs":
F="$JAVA_HOME/lib/security/blocked.certs"
head -1 "$F"
cat > /tmp/emudhra16.txt <<'L'
0164D7CEAE5BB909C272AF151FF44B1177AE9B47D9424B94F1D9558C30934D19
42C4ACCD12C4F59597925E1A08A7A90102608543809308D50EC427E118BA1493
432EC25F0D28DE9006D97BF752F17BBB2CD41F669933FCB072D9A1148D0261F3
45A883F349AEDFD5F3A649B5498FFB121712BA8B448F3F2A91DBC5A766FCDDBE
4B2460A466F95FD40113BCDCCA2CEB29B3B093921DE45474DA7DF48874C630B1
579480AEA166290BD3C643589E795FC0D0E54E86505D180F1DFF99EFD3199512
5F1DED4DD590AF74631290CF073B122A2AAC6A1FA479778A0BD43579BD832699
62B7F9868263F72F6911FC78CEAF72C1979158B7368BF648683BB2AA39B02E72
7485B51C0ED192878FA1D2F948FB529AE1842CC5086C4B67F7BE5B2039DE9489
84112972B8E59D14560AE7E7119654474AAD119990CF3722BFC1E3B91615E1FD
98B896625C0C230ADEEC3EB2CF6AAD5001ECF9156A68644E82374CE5833BC25B
9E39DE2881273ACC225A149C72BA3E0F51424963669AB633EE1DC7DF5DB067B4
A496E23AC0CAB8155FC9B117B97EAE368EFCBB9041AEC8804D5A308D2D01C2D8
CB6E15165AC802E9B3F993F16C25D41F4E81C21EBDE71AE1B012AC00BF9C7C3F
E7568FE6E12331F4FD7DE61DA4C7559D0F8EB192A218D4741A3BA75184333838
FD9D5C2DBBD4995AB69B8D50C439D9527B00529199C2FD01B2174EB58F07021F
L
grep -c -x -F -f /tmp/emudhra16.txt "$F"如何解读结果:
- cacerts 中两个根证书都没有:这个 JDK 不信任该证书链,尽管它没有拦截。测试这些命令所用的 Temurin 21.0.13,以及 Temurin 25.0.5,就是这种情况。相反,这两个分支最新发布的版本 Temurin 8u504 和 11.0.32.1 确实带有 emSign ECC Root CA - G3。
- cacerts 中有根证书,blocked.certs 中有 16 个:拦截已经生效。
- cacerts 中有根证书,blocked.certs 中少于 16 个:这个 JDK 会接受该证书链。必须更新它或应用 Oracle 的 blocked.certs,并重启 Java 应用。OpenJDK 公告列出的受影响版本是 27.0.1、25.0.5、21.0.13、17.0.21、11.0.32.1、8u504 及更早版本。
- Debian 或 Ubuntu 的 JDK:其信任库是 /etc/ssl/certs/java/cacerts,由 ca-certificates-java 软件包管理。更新系统证书后,Jackson 的页面建议以 root 身份用“touch /var/lib/ca-certificates-java/fresh”和“dpkg-reconfigure ca-certificates-java”重新生成它。
要验证结果,可以使用修复指南中的同一个 jshell 测试,它会尝试连接 Jackson 的一台测试服务器,该服务器提供由这些中间 CA 构成的证书链:
"$JAVA_HOME/bin/jshell" <<'JAVA'
import java.net.*;
import javax.net.ssl.*;
var url = URI.create("https://dv-g3b-emudhra.we-have-a-problem.com/").toURL();
try {
var c = (HttpsURLConnection) url.openConnection();
c.setConnectTimeout(10000);
c.setReadTimeout(10000);
System.out.println("WARNING: TLS ACCEPTED: " + c.getResponseCode());
} catch (SSLHandshakeException e) {
System.out.println("TLS REJECTED: " + e.getMessage());
} catch (Exception e) {
System.out.println("INCONCLUSIVE: " + e);
}
/exit
JAVA拦截生效时,输出必须是“TLS REJECTED”,并带有“Untrusted certificate: CN=EM DV TLS CA - G3B”。在不带这些根证书的 Temurin 21 和 25 上,拒绝会显示为“PKIX path building failed”。在测试中,一个 cacerts 中有两个根证书且使用原始 blocked.certs 的 JDK,返回了“WARNING: TLS ACCEPTED: 200”。
如果既无法更新,也无法替换该文件,OpenJDK 公告还建议用“-Dcom.sun.net.ssl.checkRevocation=true -Dcom.sun.security.enableCRLDP=true”启用吊销检查,并在 JDK 17 或更高版本中用“jarsigner -verify -revcheck -strict”验证已签名的 JAR。
针对攻击途径 B:下载内容的完整性
下载的内容必须对照攻击者无法控制的东西来检查:事先固定的哈希或 digest,或用已知密钥做的签名。按工具:
- 镜像:在 Dockerfile 的 FROM 和部署中按 digest 引用(“image@sha256:…”),而不只是按 tag。并按 Python 通知的要求,不使用缓存重新构建:“docker build --pull --no-cache”。
- npm:基于纳入版本控制的 lockfile,用“npm ci”安装。lockfile 的 integrity 保护已经固定的内容;新软件包必须从已更新的网络和客户端添加。
- 镜像和制品的签名:部署前用 cosign/Sigstore 验证,并要求预期的身份。接受任何签名的验证起不到任何作用。
- apt 和 rpm:不要安装没有签名的软件源,也不要为了绕过错误把它们标记为可信。
- 脚本:不要使用“curl | sh”;先下载脚本,如果项目发布了哈希或签名就加以检查,然后再运行。
对于 Python,可以用 pip 的哈希检查模式。使用 --require-hashes 时,pip 要求每个软件包都有哈希,下载内容不匹配时就会停止。uv 可以生成带哈希的文件:
uv --version
mkdir -p /tmp/emudhra-uv && cd /tmp/emudhra-uv
echo "certifi>=2026.10.19" > requirements.in
uv pip compile requirements.in --generate-hashes -o requirements.txt
grep -A1 "^certifi" requirements.txt请用已经更新的工具、从你控制的网络生成哈希。基于被拦截的下载计算出的哈希,固定的是错误的软件包。
带哈希的安装如下:
python3 -m venv /tmp/emudhra-hash && . /tmp/emudhra-hash/bin/activate
cd /tmp/emudhra-hash
cat > requirements.txt <<'REQ'
certifi==2026.10.19 \
--hash=sha256:42d35340cc5b9ba78e818ddbff0c5b1c2b779de448a340fd1b989f5fa8670e1b
REQ
python3 -m pip install --require-hashes -r requirements.txt如果下载的软件包不是预期的那个,pip 会在安装前停止。故意改动哈希后,输出如下:
ERROR: THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS FILE.
certifi==2026.10.19 from https://files.pythonhosted.org/packages/.../certifi-2026.10.19-py3-none-any.whl
Expected sha256 00d35340cc5b9ba78e818ddbff0c5b1c2b779de448a340fd1b989f5fa8670e1b
Got 42d35340cc5b9ba78e818ddbff0c5b1c2b779de448a340fd1b989f5fa8670e1b构建用的 secret 不应放在构建参数或环境变量中:Docker 文档指出它们不适合这种用途,并建议使用 secret mount。
针对攻击途径 D:Windows 上的代码签名
据 Jackson 的页面,Microsoft 通过 Windows 受信任证书列表的自动更新来分发对这些中间 CA 的拦截。第一件事是让各台机器都能收到这些更新。
有效的签名不足以让人信任一个二进制文件。运行下载的软件之前,最好先检查是谁签的名:在 PowerShell 中,Get-AuthenticodeSignature 会显示签名者的证书。证书链经过 EM OV CS CA - G3B 或 EM OV CS CA - G3C 的二进制文件不应运行。
针对攻击途径 E:固定你所信任的对象
防御方法是不把签名者的身份交给公共信任库来判断:
- 用带外共享的固定密钥或证书验证,或用 HMAC,或用你已配置的签发方 JWKS 并按“kid”解析密钥。
- 不要把令牌或消息自带的证书用作验证密钥。
- 在 signxml 中,用 x509_cert= 传入预期的证书,或用 ca_pem_file= 传入你的 CA;cert_subject_name 只检查名称。
- 对于 mTLS,用私有 CA 签发客户端证书,并在服务器上只加载这个 CA。
- 验证证书链时要求用途(EKU)。
- 在服务器端保留业务校验:限值、基于角色的授权和对账。
本周要检查什么
- 每个访问互联网的客户端使用哪个运行时和哪个信任库,包括 CI job 和 agent。
- 每台机器和每个镜像中有多少个 JDK;其中包含 emSign ECC Root CA - G3 或 AAA Certificate Services 的,blocked.certs 中是否已有 16 个指纹,相应的应用之后是否已重启。
- 每个镜像中的 pip、uv 和 certifi 是否达到 Python 通知中的最低版本,镜像是否已在不使用缓存的情况下重新构建。
- 镜像是否按 digest 引用,npm 是否从 lockfile 安装,生产环境的 requirements 是否使用哈希。
- 是否有代码关闭了 TLS 验证。
- 哪些令牌经过了未更新的客户端,是否值得轮换。
- Windows 机器是否能收到证书的自动更新。
- 哪些自动决策依赖没有签名、没有第二来源或没有限值的外部数据。
- 哪些签名验证器或客户端证书验证器会接受任何能到达公共信任库的证书链。
只要 TLS 根证书保持最新,或者 8 个中间 CA 已被拦截,伪造的证书就会失效;哈希和签名则为下载的内容再加一道屏障。
如果你想就自己的服务或构建讨论这些检查,可以通过联系页面给我们留言;请在留言中提到本文以及你所考虑的服务或 pipeline,不要包含 secret、令牌或机密的运营资料。
参考来源
2026 年 10 月 23 日查阅的来源。已在 Linux(Debian)上运行并保存输出:版本清单、grep、用 uv 生成哈希、带哈希的安装(正确的和改动过的),以及在 Temurin JDK 和添加了根证书的副本上运行的 Java 命令(分别使用原始 blocked.certs 和包含 16 个指纹的 blocked.certs),包括用 jshell 连接 Jackson 的测试服务器。未运行:docker、npm、cosign 和 PowerShell,也没有在 macOS 或 Windows 上运行任何内容。
- Mozilla Bugzilla 2083449:事件报告
- Python Discourse:给 Python 用户的信息
- Cloudflare Blog,2026/10/20
- Google Security Blog,2026/10/20
- Mozilla Security Blog,2026/10/20
- Dennis Jackson:事件概述
- Dennis Jackson:受影响的中间 CA
- Dennis Jackson:中间 CA 的根证书
- 该 CA 关于此事件的声明
- Node.js:2026 年 10 月的漏洞修复版本
- OpenJDK:2026/10/21 漏洞公告
- Oracle Security Alert CVE-2026-91403
- Oracle JDK 25.0.5.0.2:版本说明
- Oracle JDK 8u511 b32:版本说明
- Oracle JDK 8u511:版本说明
- jdk.java.net 上的 OpenJDK 27.0.1.0.2
- Amazon Corretto 25:CHANGELOG
- Amazon Corretto 8:CHANGELOG
- Homebrew:openjdk formula
- OpenJDK:cacerts
- Docker Desktop 版本说明,4.96.3
- RFC 7515:JSON Web Signature
- signxml:建立信任
- cryptography:X.509 验证
- pip:哈希检查模式
- uv:CLI 参考
- Docker:build secrets
- Docker:build variables


