跳到主要内容
AI-native 工程

macOS 上的 eMudhra:curl、Node、Python、Go、Java、Rust 和 Docker 需要更新什么

macOS 已经拦截 eMudhra 的中间 CA,但 curl、Node、pip、Java 和容器(Docker)使用各自的根证书:需要更新什么,以及如何检查。

发布 更新 11 分钟阅读
securityTLScertificatesDevOpsmacOS

本文仅用于教育目的,不能替代正式的智能合约审计、法律建议、金融建议或针对具体协议的安全审查。

eMudhra 的八个中间 CA(六个用于 TLS,两个用于代码签名)在生成时使用的私钥,任何人都能从证书本身推算出来;用其中六个 TLS 中间 CA 可以为任意域名签发有效证书。Chrome 和 Firefox 自 2026 年 10 月 17 日起拦截它们,Microsoft 自 20 日起;据 Dennis Jackson 的页面,Apple 自 22 日起。许多开发工具并不查询这些拦截措施,而是依据自己的根证书列表做判断。

在 Mac 上,Apple 的拦截覆盖使用系统验证器的程序,例如 Safari、Go 和 rustls-platform-verifier。它不覆盖系统自带的 curl 和 python3、Node、pip、Java,也不覆盖 Docker 的 Linux 容器,它们都带有自己的根证书。把每个工具更新到已修复的版本,重新构建内置根证书的程序,并针对公共服务器进行测试。正确的结果是证书错误;返回 200 说明该工具仍然信任这些中间 CA。

大理石底座上排成一排的七块玻璃:五块钴蓝色的已经验证,一只手正用探针检查一块琥珀色的,还有一块透明的尚未检查。
概念示意图。

发生了什么,为什么只靠浏览器不够

2026 年 10 月 17 日,一名研究人员通知 Apple、Google、Microsoft 和 Mozilla 的根证书计划:eMudhra 的八个中间 CA 的密钥强度不足。Google 指出,签发这些已被攻破的中间 CA 的根证书是 emSign ECC Root CA - G3;此外还有一条经由 Sectigo 的 AAA Certificate Services 根证书交叉签名的备用路径,而旧的根证书列表仍然包含这个根证书。

Chrome 在同一天 19:45 UTC(马德里时间 21:45)通过 CRLSet 更新拦截了这些中间 CA 的公钥。Mozilla 在 22:59 UTC(马德里时间 18 日 00:59)通过 OneCRL 完成拦截,发布了 Firefox 158.0.1,并在 NSS 3.131.1 版本中移除了该根证书。Google 将于太平洋时间 10 月 27 日星期二上午从其根证书库中移除该根证书。

据 eMudhra 称,八个中间 CA 中只有一个投入生产使用,且没有一个签发过最终实体证书。Google 和 Mozilla 的 Dennis Jackson 一致表示,Certificate Transparency(CT)日志中没有这些中间 CA 签发的证书,因此要求 CT 的浏览器不可能受到攻击。风险在于既不要求 CT、也不查询吊销信息的程序:curl、各语言的 runtime、pip 和容器镜像。要让这些程序不再信任这些中间 CA,需要更新它们的根证书列表或代码。

仅靠一个被攻破的中间 CA 不足以发起攻击。攻击者还需要控制工具与服务器之间的网络、DNS 或代理。具体的攻击向量以及如何阻断,见另一篇文章。

如何解读测试结果

Mozilla 的 Dennis Jackson 维护着一台测试服务器,其证书链由受影响的中间 CA 之一 EM DV TLS CA - G3B 签发。如果某个工具成功连接,说明它仍然信任该中间 CA;如果返回证书错误,则说明不再信任。

具体的错误信息因工具和版本而异:“unable to get local issuer certificate”“certificate revoked”“no valid chains built”“CertDistrusted”或“PKIX path building failed”含义相同。如果测试没有响应或 DNS 解析失败,结果说明不了任何问题:请重试。

同一页面还记录了服务器的几个变体。带有“-aaa-”的变体经由 Sectigo 的交叉签名,带有“-noct-”的变体使用一张从未记录到 CT 中的证书。如果某个工具接受了没有 CT 的变体,说明它信任这些中间 CA,而且也不要求 CT。

Cloudflare 提醒了一个重要细节:测试只对被测试的那条验证路径有效。浏览器或 curl 拒绝该证书链,并不能说明使用另一个 TLS 库的应用会怎样。

curl

macOS 的 curl,和系统自带的 git、python3、perl、ruby 和 openssl 一样,依据 /etc/ssl/cert.pem 进行验证且不查询吊销信息,而这个文件并没有更新。Jackson 的页面公布了一个使用 sudo 的步骤,用于从该文件中删除两个受影响的根证书。它会修改系统文件,所以最好先完整阅读并做出决定,再去执行。

Homebrew 的 curl 使用 Homebrew 的 OpenSSL,后者从 ca-certificates formula 获取根证书。已修复的版本是 2026-09-25_1 或更高。更新它们,并专门用这个 curl 进行测试:

bash
brew update
brew upgrade ca-certificates curl
brew list --versions ca-certificates curl
"$(brew --prefix curl)/bin/curl" -v -o /dev/null https://dv-g3b-emudhra.we-have-a-problem.com/
echo "exit: $?"

预期结果是“SSL certificate problem: unable to get local issuer certificate”,退出码为 60。如果退出码为 0 并出现“HTTP/1.1 200 OK”,说明这个 curl 仍然信任该证书链。curl 不要求 CT,因此正是 Jackson 页面所描述的那类客户端。

Node.js

Node 在二进制文件中自带一份 Mozilla 根证书的副本,因此 macOS 做什么都不会影响它。已修复的版本是 26.12.1、24.22.1 和 22.23.4:它们把根证书更新到 NSS 3.131.1,并加入了对已拦截公钥的拒绝。如果你使用 nvm、fnm 或 Volta,请更新已安装的每一个版本,而不只是当前启用的版本。

bash
node --version
node <<'NODE'
const https = require('node:https');

const req = https.get({
  hostname: 'dv-g3b-emudhra.we-have-a-problem.com',
  timeout: 10000,
  rejectUnauthorized: true
}, res => {
  console.log('WARNING: TLS ACCEPTED:', res.statusCode);
  res.resume();
});

req.on('error', err => {
  console.log('REQUEST REJECTED:', err.code, err.message);
});

req.on('timeout', () => {
  console.log('INCONCLUSIVE: timeout');
  req.destroy();
});
NODE

使用 Node 24.22.1 时,输出为“REQUEST REJECTED: CERT_REVOKED certificate revoked”。使用未修复的旧版本(例如 20.19.2)时,输出为“WARNING: TLS ACCEPTED: 200”。还要检查 NODE_EXTRA_CA_CERTS、NODE_TLS_REJECT_UNAUTHORIZED=0 以及代码中任何 rejectUnauthorized: false,因为它们会改变 Node 接受的内容。

Python、pip 和 uv

在 Python 中需要更新两份根证书列表。解释器的那一份取决于你的安装方式。pip 的那一份就在 pip 内部:根据 Python 官方关于此事件的讨论帖,pip 除了系统根证书库之外,总会加载它自带的 certifi 副本,而 REQUESTS_CA_BUNDLE 或 --cert 等选项只会添加根证书。可靠的修复方法是更新 pip。

Python Software Foundation 公布的最低版本是 certifi 2026.10.19、pip 26.2.2 和 uv 0.13.4。Python 3.15.1、3.14.9 和 3.13.17 已经包含 pip 26.2.2。如果 pip 版本较旧,更新过程本身也会使用旧的根证书,所以 PSF 建议在命令中固定软件包的哈希值。在每个虚拟环境中运行:

bash
python3 -m pip --version
python3 -m pip install "pip @ https://files.pythonhosted.org/packages/3f/06/3e4420302363fbb71be3c7f35ce042f54bfca330e3e66b3a2e3c4cca579f/pip-26.2.2-py3-none-any.whl#sha256=fd7f4dfa8190e014013b9f08f3e973f4e4c26ffd179a204895533a7254813a70"
python3 -m pip install --upgrade "certifi>=2026.10.19"
python3 -m pip debug --verbose | grep certifi

最后一行应显示 certifi==2026.10.19,即 pip 自带的副本。如果 uv 是用其自带的安装程序安装的,PSF 给出的命令是“UV_SYSTEM_CERTS=true uv self update”;如果是用 Homebrew 安装的,则是“brew upgrade uv”。

要检查一个环境中的两份列表,请用该环境的 python3 运行这个测试:

python
import ssl
import socket
import certifi

host = "dv-g3b-emudhra.we-have-a-problem.com"

contexts = {
    "default": ssl.create_default_context(),
    "certifi": ssl.create_default_context(cafile=certifi.where()),
}

for name, ctx in contexts.items():
    try:
        with socket.create_connection((host, 443), timeout=10) as sock:
            with ctx.wrap_socket(sock, server_hostname=host):
                print(name, "WARNING: TLS ACCEPTED")
    except ssl.SSLCertVerificationError as exc:
        print(name, "TLS REJECTED:", exc.verify_message)
    except Exception as exc:
        print(name, "INCONCLUSIVE:", repr(exc))

使用 certifi 2026.10.19 时,certifi 这一行应显示“TLS REJECTED: unable to get local issuer certificate”。default 这一行取决于该解释器使用的根证书库:如果显示 ACCEPTED,请更新系统根证书库或安装程序自带的根证书库。

Go

在 macOS 上,Go 把验证交给系统 API,因此 Mac 上的 Go 程序会继承 Apple 的拦截。问题出在你在 Mac 上为 Linux 编译的二进制文件,例如用于容器的文件:在那里 Go 使用自己的验证器。Go 1.27.3 和 1.26.10 在 crypto/x509 中加入了一份已拦截公钥的列表(CVE-2026-111943)。用“brew upgrade go”或官方安装程序更新 Go,然后重新编译并部署每个二进制文件。

要进行测试,请在 Linux 上或在运行该二进制文件的容器内运行:

bash
go version
mkdir -p /tmp/emudhra-go && cd /tmp/emudhra-go
cat > main.go <<'EOF'
package main

import (
	"fmt"
	"net/http"
	"time"
)

func main() {
	client := &http.Client{Timeout: 10 * time.Second}
	resp, err := client.Get("https://dv-g3b-emudhra.we-have-a-problem.com/")
	if err != nil {
		fmt.Println("TLS REJECTED:", err)
		return
	}
	resp.Body.Close()
	fmt.Println("WARNING: TLS ACCEPTED:", resp.Status)
}
EOF
go run main.go

在 Linux 上使用 Go 1.27.3 时,输出以“x509: no valid chains built”结尾。在根证书库未更新的环境中使用 1.27.2 时,输出以“200 OK”结尾。已经编译好的二进制文件内含编译时所用的 Go 版本;在“go version”后面加上二进制文件的路径即可查看。

Java

10 月 21 日之前发布的 JDK 默认不会拦截这些中间 CA,你已经安装的 JDK 如果早于这个日期,也同样不会。请更新到已修复的版本(Oracle 或 OpenJDK 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,Oracle JDK 8u511 b32,Corretto 25.0.5.0.9 / 21.0.13.0.10 / 8.512.08.1,或版本号相同的 Homebrew openjdk / @21 / @17)。如果无法更新,请从已修复的 JDK 复制 lib/security/blocked.certs(JDK 8 中为 jre/lib/security/blacklisted.certs),确认其中包含这 16 个 SHA-256 指纹,然后重启 Java 应用。Oracle 也在 ops.java/emudhra 发布了该文件,但该页面在 10 月 23 日无法访问。

Java 在每个 JDK 中使用自己的根证书库 cacerts,不会参考 macOS 的拦截。如果该 cacerts 包含 emSign ECC Root CA - G3 或 AAA Certificate Services,只要这些中间 CA 不在 JDK 的证书拦截列表中,JDK 就会接受它们。OpenJDK 10 月 21 日的公告(CVE-2026-91403)列出的受影响版本为 27.0.1、25.0.5、21.0.13、17.0.21、11.0.32.1、8u504 以及各自更早的版本。

这项修复在 OpenJDK 中的编号是 JDK-8395142,在 Oracle 的版本说明中是 JDK-8395555。它不会删除任何根证书,而是把 eMudhra 的 8 个中间 CA 和 8 个由 Sectigo 交叉签名的证书加入拦截列表。修复已发布在 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,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、Zulu 以及 Temurin 8 和 11 仍未包含修复。Temurin 21 和 25 同样没有这项修复,但由于它们既不带 G3 也不带 AAA,会拒绝这条证书链。

在 Oracle JDK 8 中,10 月 20 日发布的 8u511(1.8.0_511-b09)仍受影响;已修复的是 8u511 b32(1.8.0_511-b32,10 月 21 日发布)。请用“java -version”检查:如果输出中没有“b32”,请更新。在 OpenJDK 8(Temurin、Zulu 等)中,8u504 及更早版本受影响;截至 10 月 23 日,Temurin 尚未发布修复,Corretto 8.512.08.1 已包含修复。

主要做法是更新。对于 Homebrew 安装的 JDK:

bash
/usr/libexec/java_home -V
brew list --versions | grep openjdk
brew upgrade openjdk
brew upgrade openjdk@21
brew upgrade openjdk@17
for f in openjdk openjdk@21 openjdk@17; do
  J="$(brew --prefix "$f")/bin/java"
  [ -x "$J" ] && echo "$f:" && "$J" -version
done

只更新你已安装的 formula。第一行并不会列出所有 JDK,只会列出在 /Library/Java/JavaVirtualMachines 或 ~/Library/Java/JavaVirtualMachines 中有链接的 JDK。Homebrew 的 keg-only formula(例如 openjdk@21 或 openjdk@17)只会在“brew list --versions”或“brew --prefix openjdk@21”中出现,需要逐个检查。只看名称不够:请把每个 JDK 的实际版本与上面的列表对照。“brew list --versions”应显示 openjdk 27.0.1.0.2、openjdk@21 21.0.13.0.2 或 openjdk@17 17.0.21.0.2;openjdk 27 或 openjdk@21 21.0.13 仍受影响。最后的循环会打印每个 formula 的“java -version”。IDE 或 SDKMAN! 安装的 JDK 需要用各自的安装程序更新。

下面这段代码把 16 个 SHA-256 指纹保存到 /tmp/emudhra16.txt,并统计 Mac 上每个 JDK 的拦截列表中包含其中多少个。在 JDK 11 及更高版本中,该文件名为 blocked.certs;在 JDK 8 中为 blacklisted.certs,位于 jre 文件夹内:

bash
cat > /tmp/emudhra16.txt <<'EOF'
0164D7CEAE5BB909C272AF151FF44B1177AE9B47D9424B94F1D9558C30934D19
42C4ACCD12C4F59597925E1A08A7A90102608543809308D50EC427E118BA1493
432EC25F0D28DE9006D97BF752F17BBB2CD41F669933FCB072D9A1148D0261F3
45A883F349AEDFD5F3A649B5498FFB121712BA8B448F3F2A91DBC5A766FCDDBE
4B2460A466F95FD40113BCDCCA2CEB29B3B093921DE45474DA7DF48874C630B1
579480AEA166290BD3C643589E795FC0D0E54E86505D180F1DFF99EFD3199512
5F1DED4DD590AF74631290CF073B122A2AAC6A1FA479778A0BD43579BD832699
62B7F9868263F72F6911FC78CEAF72C1979158B7368BF648683BB2AA39B02E72
7485B51C0ED192878FA1D2F948FB529AE1842CC5086C4B67F7BE5B2039DE9489
84112972B8E59D14560AE7E7119654474AAD119990CF3722BFC1E3B91615E1FD
98B896625C0C230ADEEC3EB2CF6AAD5001ECF9156A68644E82374CE5833BC25B
9E39DE2881273ACC225A149C72BA3E0F51424963669AB633EE1DC7DF5DB067B4
A496E23AC0CAB8155FC9B117B97EAE368EFCBB9041AEC8804D5A308D2D01C2D8
CB6E15165AC802E9B3F993F16C25D41F4E81C21EBDE71AE1B012AC00BF9C7C3F
E7568FE6E12331F4FD7DE61DA4C7559D0F8EB192A218D4741A3BA75184333838
FD9D5C2DBBD4995AB69B8D50C439D9527B00529199C2FD01B2174EB58F07021F
EOF

for JDK in /Library/Java/JavaVirtualMachines/*/Contents/Home \
           "$HOME"/Library/Java/JavaVirtualMachines/*/Contents/Home \
           /opt/homebrew/opt/openjdk*/libexec/openjdk.jdk/Contents/Home \
           /usr/local/opt/openjdk*/libexec/openjdk.jdk/Contents/Home; do
  [ -x "$JDK/bin/java" ] || continue
  F="$JDK/lib/security/blocked.certs"
  [ -f "$F" ] || F="$JDK/jre/lib/security/blacklisted.certs"
  N="$(grep -c -x -F -f /tmp/emudhra16.txt "$F" 2>/dev/null)"
  echo "$JDK: ${N:-0}/16 eMudhra fingerprints in $(basename "$F")"
done

已修复的 JDK 会显示 16/16。少于 16 个,说明它仍未受到保护。

要测试某个特定的 JDK,请在 PATH 中使用它的 java 和 jshell 运行:

bash
java -version
cat > /tmp/emudhra-java.jsh <<'EOF'
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
EOF
jshell /tmp/emudhra-java.jsh

应用拦截列表后,输出为“TLS REJECTED: (certificate_unknown) PKIX path validation failed”,后面跟着“Untrusted certificate: CN=EM DV TLS CA - G3B”。在 Temurin 21 和 25 中,由于没有该根证书,输出为“PKIX path building failed”。不同的 Java 发行版文字会有所不同;关键是不要出现“TLS ACCEPTED”。

如果某个 JDK 无法更新,例如 openjdk@11 或 openjdk@8,就需要把这些指纹加入它的拦截列表。可以使用同一版本的已修复 JDK 中的 blocked.certs,或 /tmp/emudhra16.txt 中的 16 个指纹,它们与 OpenJDK 中 JDK-8395142 的 PEM 文件一致。Oracle 也在 ops.java/emudhra 发布了该文件,但该页面在 10 月 23 日无法访问。该文件以 Algorithm=SHA-256 这一行开头,之后每行一个十六进制指纹。下面这段代码会校验源文件,要求包含全部 16 个指纹,保留每个 JDK 中已有的条目,保存一份不会被覆盖的 .pre-emudhra 副本,并遍历与上面检查相同的 JDK:

bash
SRC=/tmp/emudhra16.txt
(
  [ -s "$SRC" ] || { echo "ERROR: missing $SRC"; exit 1; }
  grep -Evx 'Algorithm=SHA-256|[0-9A-Fa-f]{64}' "$SRC" | grep -q . && { echo "ERROR: unexpected format"; exit 1; }
  [ "$(tr 'a-f' 'A-F' < "$SRC" | grep -c -x -F -f /tmp/emudhra16.txt)" = 16 ] || { echo "ERROR: missing eMudhra fingerprints"; exit 1; }
  for JDK in /Library/Java/JavaVirtualMachines/*/Contents/Home \
             "$HOME"/Library/Java/JavaVirtualMachines/*/Contents/Home \
             /opt/homebrew/opt/openjdk*/libexec/openjdk.jdk/Contents/Home \
             /usr/local/opt/openjdk*/libexec/openjdk.jdk/Contents/Home; do
    [ -x "$JDK/bin/java" ] || continue
    F="$JDK/lib/security/blocked.certs"
    [ -f "$F" ] || F="$JDK/jre/lib/security/blacklisted.certs"
    [ "$(head -n 1 "$F" 2>/dev/null)" = "Algorithm=SHA-256" ] || { echo "SKIPPED: $JDK"; continue; }
    [ -e "$F.pre-emudhra" ] || cp -p "$F" "$F.pre-emudhra" || exit 1
    {
      echo "Algorithm=SHA-256"
      { tail -n +2 "$F"; grep -Ex '[0-9A-Fa-f]{64}' "$SRC"; } | tr 'a-f' 'A-F' | sort -u
    } > "$F.tmp" && cat "$F.tmp" > "$F" && rm "$F.tmp" || exit 1
    echo "$JDK: $(grep -c -x -F -f /tmp/emudhra16.txt "$F")/16; entries before: $(($(wc -l < "$F.pre-emudhra") - 1)); after: $(($(wc -l < "$F") - 1))"
  done
  echo "Restart all running Java applications: blocked.certs is only read when the JVM starts."
)

如果要使用 Oracle 的文件或已修复 JDK 中的文件,请把第一行改成它的路径。每个 JDK 最终都应为 16/16。/Library/Java/JavaVirtualMachines 中的 JDK 需要管理员权限:请在用 sudo -s 打开的 shell 中运行这段代码。Java 只在启动时读取该列表,所以需要重启正在运行的 Java 应用、IDE 和服务器。Homebrew 更新会用新版本的文件替换它:如果新版本已修复,就没有影响;如果没有,请重新运行这段代码。

OpenJDK 公告还提出了另一种临时替代方案:用“-Dcom.sun.net.ssl.checkRevocation=true -Dcom.sun.security.enableCRLDP=true”启用吊销检查。用 keytool -delete 删除根证书并不是这项修复的做法;修复保留根证书,只拦截这 16 个证书。删除 AAA Certificate Services 还会影响所有依赖它的证书,而且 Dennis Jackson 的页面指出,不建议普通用户对这些根证书取消信任。

Rust

在 Rust 中,修复不取决于编译器版本,而取决于每个项目的 Cargo.lock。rustls-webpki 0.103.16 会拒绝已拦截的密钥(RUSTSEC-2026-0382),webpki-roots 1.0.10 移除了根证书 emSign ECC Root CA - G3。在 macOS 上,rustls-platform-verifier 使用系统验证器,但在 Linux 上它使用 webpki,因此风险又一次落在你部署到容器中的二进制文件上。在每个项目中运行:

bash
cargo tree -i rustls-webpki
cargo update -p rustls-webpki
cargo tree -i rustls-webpki

更新之后,“cargo tree”应显示 rustls-webpki v0.103.16 或更高版本。如果项目使用 webpki-roots,用“cargo update -p webpki-roots”做同样的操作,更新到 1.0.10。然后重新编译并部署。如果你使用 rustup,用“rustup self update”把它更新到 1.29.2。

Docker

10 月 22 日发布的 Docker Desktop 4.96.2 撤销了对被攻破的中间 CA 的信任。这覆盖了 Docker CLI 和 daemon 的连接,但不覆盖镜像:每个镜像都带有自己的根证书列表,以及自己的 Python、Node、Java 或 Go 版本。

从应用中或用“brew upgrade --cask docker-desktop”更新 Docker Desktop,并在不使用缓存的情况下重新构建镜像,以免复用带有旧根证书的层:

bash
docker version --format '{{.Server.Platform.Name}}'
docker build --pull --no-cache -t my-image:emudhra .
docker run --rm my-image:emudhra python3 -m pip --version

最后一行是针对包含 Python 的镜像的示例:在镜像内应显示 pip 26.2.2 或更高版本。对于其他镜像,请在容器内运行相应语言的测试。如果基础镜像尚未发布已修复的版本,请在你自己的 Dockerfile 中更新发行版的 ca-certificates 软件包或 runtime。

检查清单

  • Homebrew:ca-certificates 2026-09-25_1 或更高版本,并已用 Homebrew 的 curl 针对测试服务器进行测试。
  • 系统自带的 curl、git 和 python3:已决定并记录针对 /etc/ssl/cert.pem 的处理方式。
  • Node:每个已安装的版本都是 26.12.1、24.22.1 或 22.23.4。
  • Python:每个虚拟环境中都是 pip 26.2.2 和 certifi 2026.10.19;uv 0.13.4。
  • Go:1.27.3 或 1.26.10,二进制文件已重新编译并部署。
  • Java:每个 JDK(包括 Homebrew 的 keg-only formula)都是已修复的版本(看完整版本号,而不只是名称);如果无法更新,则 blocked.certs 中已包含这 16 个指纹(16/16)或已启用吊销检查,并已重启 Java 应用。
  • Rust:每个 Cargo.lock 中都是 rustls-webpki 0.103.16,二进制文件已重新编译。
  • Docker:Desktop 4.96.2 或更高版本,镜像已在不使用缓存的情况下重新构建。
  • 已检查会关闭验证或添加根证书的变量和选项。

拒绝连接不能证明什么

测试中出现证书错误,说明该工具在该版本下已不再信任这些中间 CA。它不能说明同一台 Mac 上的其他工具、其他虚拟环境或某个容器的情况。它也不能代替检查:在问题尚未解决期间,是否有连接可能经过了你无法控制的网络。

要在 macOS 和 CI 中了结 eMudhra 事件,请逐一更新这 7 个工具,并保存每项测试的输出以及日期和版本。这是证明修复已在关键之处生效的最简单的证据。

参考来源

2026 年 10 月 23 日查阅的来源。已在 Linux(Debian 13)上运行并保存输出:curl、Node、Python、Go、Java 和 Rust 的测试,带哈希值的 pip 更新,以及在测试路径中的 JDK 副本上进行的 16/16 检查和 blocked.certs 合并。已于 10 月 23 日在一台真实的 Mac(macOS 27.0.1,arm64)上以只读方式检查:/usr/libexec/java_home -V、/Library/Java/JavaVirtualMachines 和 brew list --versions。未在 macOS 上运行:brew upgrade、brew --prefix、sudo -s、脚本中的 Homebrew 路径,以及 /etc/ssl/cert.pem。未运行:Docker。

需要把这些方法应用到你的上线或工作流吗?

申请技术审查,我们会一起梳理最安全的第一步。

相关文章