前言
近期,OpenJDK 官方披露了 CVE-2026-91403 高危漏洞。该漏洞的根源在于 Java JSSE 组件内置的信任库中,包含了受影响的 eMudhra (emSign) 根/中间证书。一旦攻击者利用泄露的私钥伪造域名证书,那些主动向外部发起 HTTPS 请求的 Java 应用(如支付网关、服务调用方)将面临中间人攻击的严重威胁。
然而,在处理这次漏洞时,我们遇到了两个运维痛点:
- 系统机制差异 :在 Rocky Linux 9 等红帽系系统中,底层证书受 RPM 保护,不能像 Ubuntu 那样直接
rm删除。 - 环境复杂:老旧服务器上往往"缝缝补补",同时存在多个系统 JDK、独立部署的 JDK 甚至中间件自带的 JDK。
本文记录了我们在 Rocky Linux 9 环境下,如何通过"系统底层拆解拉黑"、"多版本 JDK 逐个清理"以及"统一业务运行环境"的方式,彻底闭环该漏洞的完整实操过程。
一、 核心修复思路
由于 Rocky Linux 底层证书受保护,我们的修复策略分为两步:
- 系统层 :采用"拆解拉黑法"。将系统大证书包拆解,提取目标坏证书放入
blocklist黑名单目录,触发系统重新生成信任链。 - Java 层 :盘点全系统 JDK,清理
cacerts物理库残留,并将独立安装的 JDK 统一替换为系统自带的最新 OpenJDK,便于后续维护。
二、 完整实操步骤
1. 系统底层证书清理(拆解拉黑法)
bash
# 创建系统黑名单目录
sudo mkdir -p /etc/pki/ca-trust/source/blocklist/
# 拆解系统大证书包(利用 awk 将大文件拆分为多个独立的小证书文件)
mkdir -p /tmp/certs_split && cd /tmp/certs_split
sudo awk '/BEGIN CERTIFICATE/ {c++; fn="cert-" c ".pem"} c > 0 {print > fn}' /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
# 遍历拆分出的证书,精准提取 emSign 并丢入黑名单
for f in cert-*.pem; do
if openssl x509 -in "$f" -noout -subject | grep -qi "emSign"; then
sudo cp "$f" /etc/pki/ca-trust/source/blocklist/
echo "✅ 成功拉黑: $f"
fi
done
# 刷新系统信任库,使黑名单生效
sudo update-ca-trust extract

2. 全系统 JDK 环境盘点
bash
# 在多 JDK 共存的服务器上,找出所有 keytool 的路径
find / -name keytool 2>/dev/null
(预期会看到:系统 JDK、独立安装的 JDK、中间件自带的 JDK 等路径)
3. 逐个清理各版本 JDK 的残留证书
系统层的拉黑,部分系统 JDK 会自动同步,但独立部署的 JDK 不会,必须逐一验证并物理清理。
检查系统 JDK (以 17 为例):
bash
/usr/lib/jvm/java-17-openjdk-*/bin/keytool -list -cacerts -storepass changeit | grep -i emsign
- 预期结果 :无输出。如果有残留,使用
sudo keytool -delete -alias "别名" -cacerts -storepass changeit逐条删。
检查中间件自带 JDK (以 Elasticsearch 为例):
bash
/usr/share/elasticsearch/jdk/bin/keytool -list -keystore /usr/share/elasticsearch/jdk/lib/security/cacerts -storepass changeit | grep -i emsign
- 预期结果 :如果有输出,同样通过
keytool -delete删掉,然后重启对应服务。
4. 统一业务服务的 JDK 运行环境
说明:原业务可能使用了独立安装的 /opt/jdk1.8,为方便后续统一打补丁管理,建议将其统一替换为系统自带的 OpenJDK。
bash
# 备份原 systemd 配置文件
sudo cp /etc/systemd/system/<your-app-name>.service /etc/systemd/system/<your-app-name>.service.bak
# 批量替换启动路径(路径请替换为你的系统 JDK 绝对路径)
sudo sed -i 's|/opt/jdk1.8/jre/bin/java|/usr/lib/jvm/java-1.8.0-openjdk/bin/java|g' /etc/systemd/system/<your-app-name>.service
# 重载配置并重启服务
sudo systemctl daemon-reload
sudo systemctl restart <your-app-name>.service
三、 全系统终极验证
全部操作完成后,执行以下命令进行排查(除了系统信任锚允许残留正常的 C2/G2,其余必须全部无输出!):
1. 验证系统信任锚状态
bash
trust list --filter=ca-anchors | grep -i -B 2 -A 2 "emSign"
2. 验证系统 JDK
bash
/usr/lib/jvm/java-1.8.0-openjdk/bin/keytool -list -keystore /usr/lib/jvm/java-1.8.0-openjdk/jre/lib/security/cacerts -storepass changeit | grep -i emsign
3. 验证业务独立部署的 JDK
bash
/opt/jdk1.8/jre/bin/keytool -list -keystore /opt/jdk1.8/jre/lib/security/cacerts -storepass changeit | grep -i emsign
4. 验证底层大证书包
bash
awk -v cmd='openssl x509 -noout -subject' '/BEGIN/{close(cmd)};{print | cmd}' < /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem | grep -i emsign
四、 验证结果的标准判定
在执行完上述验证命令后,需按以下标准进行确认:
- 针对大证书包(第 4 条) :终端可能输出
Could not find certificate from <stdin>,这是 openssl 处理 PEM 格式时的正常提示,只要没看到具体的emSign证书主体,即视为清理成功。 - 针对各个 JDK :必须做到完全静默(无任何输出)。如果出现
Warning提示(如提示使用-cacerts),但下方没有列出具体别名,也属于安全状态。 - 服务状态确认 :验证完成后,必须使用
systemctl status <your-app-name>确认所有的 Java 业务进程已正常拉起,处于active (running)状态。
五、 📌 运维避坑指南
在本次多台服务器的清理过程中,总结了以下几条经验,供后续运维参考:
- 关于残留的
C2和G2:这两个证书不在此次 CVE 漏洞影响范围内,保留是系统的正常行为,不要去强行删除,以免破坏系统底层依赖。 - 关于老旧 JDK :某些早期发布的老版本 JDK(如
1.8.0_211)天生不包含这些坏证书,keytool查不到残留时,无需强制替换其黑名单文件。 - 备份的重要性 :在修改
systemd配置文件或清理物理文件前,务必保留.bak备份,以便在出现未知兼容性问题时能够快速回滚。 - 重启提醒 :无论是修改了系统证书库还是替换了 JDK 黑名单,必须重启对应的 Java 业务进程。因为 JVM 只有在启动时才会将信任库加载到内存中,不重启等于没修。
- 后续清理 :业务平稳运行 1 个月后,确认无回退需求,可顺手删掉
/etc/systemd/system/*.service.bak以及/tmp/certs_split等临时目录,保持系统干净。
清理前:

清理后:
