Debian 上 Java 读证书的路子跟别的发行版不一样,JDK 升过了,keystore 里却还能看到 emSign,很容易让人犯迷糊。版本号这边也有坑:Oracle 为 eMudhra 这件事单独发了一份 Security Alert(CVE-2026-91403,组件 JSSE,CVSS 9.1,10 月 21 日发布),它不在前一天的 10 月 CPU 正文里。Alert 的受影响版本一栏写的是 8u511、11.0.33、17.0.21、21.0.13、25.0.5、27.0.1,这几个号跟很多人 10 月刚升上去的版本对得上。也就是说,CPU 一出来就升级的机器,在这个 Alert 面前很可能还算没升。OpenJDK 同一天的漏洞公告也列了这个 CVE,8 到 27 几条线都受影响。
按 OpenJDK 官方的说法,Arch、Fedora、Gentoo、Oracle Linux、RHEL 上的 openjdk 包直接用系统证书,系统的 ca-certificates 升了基本就够;FreeBSD 和 Homebrew 的包压根不读系统证书,只能等包本身更新;Debian 系卡在中间,名义上用系统证书,实际上中间隔了一层要手动刷新的 keystore。所以同样是「升过 JDK」,换个发行版、换个装法,结果可能完全不一样。下面分三种情况说。
用 Oracle JDK 的
按 Alert 去升,具体该装哪个 build 看 Alert 里链接的 Patch Availability Document,别拿网上转述的版本号当准。Oracle 在 ops.java/emudhra 里写明了,Oracle JDK 的 keystore 已经把相关根证书删了。暂时升不了的,同一页给了手动删根和打开吊销检查两种办法,跟下面 OpenJDK 那段是一样的。
用 Debian 自带 openjdk 包的
OpenJDK 官方的说明页里是这么解释的:Debian 及其衍生版(Ubuntu、Devuan)的 OpenJDK 包,本意是通过 ca-certificates-java 去用系统 ca-certificates 里的证书,生成的 keystore 是 /etc/ssl/certs/java/cacerts。但 ca-certificates-java 有个老 bug,这两个包都升级了,Java 的 keystore 也不会跟着重建。官方给的绕法是用 root 删掉重来:
# rm -f /etc/ssl/certs/java/cacerts
# update-ca-certificates --fresh
做完记得把跑着的 Java 进程重启一遍,Docker 镜像里的 Debian 基础层同理,要重新 build。
系统证书包本身,Debian security tracker 上 bookworm 的修复版是 20250419~deb12u2,trixie 是 20250419+deb13u1。openjdk 包这边,CVE 页上能看到 trixie 的 openjdk-21 已经通过 DSA-6588-1 修了,bookworm 的 openjdk-17、trixie 的 openjdk-25 还标着 vulnerable,sid 里有几个已经修了。状态变得快,自己点进去看自己用的那个包。另外别拿 Oracle Alert 里的版本号去对 Debian 的包,Debian 标修没修是按自己的包版本来的(带 ~deb13u2 这类后缀),以 tracker 上写的 fixed 版本为准,光看上游版本号会看走眼。
还有一点容易误判。Red Hat 的 CVE 说明里提到,OpenJDK 上游的修复并没有删掉 emSign ECC Root CA - G3 这张根,而是直接拉黑出问题的那几张中间证书。所以光看 keystore 里有没有 emSign,判断不了 JDK 本身补没补。更靠谱的是对一下:系统那份证书已经更新了,/etc/ssl/certs/java/cacerts 却还是老样子,那基本就是没重建。要查当前 keystore 里有什么,用下面这条命令列出来,再搜 emsign:
keytool -list -keystore /etc/ssl/certs/java/cacerts
官方页还提供了一个 CheckCerts.java,JDK 8 以上都能跑,比自己肉眼翻列表省事。
自带 cacerts 的便携版和自定义 truststore
从 vendor 下载解压就用的 JDK,证书在 $JDK_HOME/lib/security/cacerts(JDK 8 是 jre/lib/security/cacerts),系统怎么升都碰不到它。OpenJDK 的说明是优先等 vendor 出新构建,release note 里要能看到 JDK-8395690。还没出的话,可以备份好 keystore,再删掉相关的根(JDK 11 及以上):
keytool -delete -cacerts -alias "emsignrootcag1 [jdk]"
keytool -delete -cacerts -alias "emsignrootcag2 [jdk]"
keytool -delete -cacerts -alias "emsigneccrootcag3 [jdk]"
keytool -delete -cacerts -alias "comodoaaaca [jdk]"
提示证书不存在的报错可以忽略。注意 comodoaaaca 删掉以后,别的链到这张根的站可能也会验不过,上线前在测试环境跑一圈。机器上装了几个 JDK 就得各删一遍。另一条路是给 java 加上 -Dcom.sun.net.ssl.checkRevocation=true 和 -Dcom.sun.security.enableCRLDP=true,打开吊销检查。
用 -Djavax.net.ssl.trustStore 指向自己那份 truststore 的,里面的别名不一定是上面这套,只能自己 keytool -list 一条条看。
上游这边,披露页的 Java 那一行还写着 OpenJDK pending,各家 vendor 的构建还在陆续出。Node、pip、Docker 那边站里另有一帖,Flutter 的后面再单独说。
你们线上的 Java 服务,用的是系统 openjdk 包、vendor 的 tarball,还是镜像里自带的 JDK?