Java 17调用getSigners返回null求助:已签名Jar无法获取签名信息
问题分析与解决方案
你遇到的问题核心是自签名证书不被Java默认信任,以及PKIX路径验证失败导致类加载器未将签名/证书信息关联到类的ProtectionDomain中,和算法支持关系不大(jarsigner能验证通过说明签名算法是兼容的)。
核心原因
- Java类加载器默认仅信任受信任CA签发的证书签名的Jar。自签名证书没有完整的信任链,PKIX路径构建失败意味着Java无法验证证书合法性,因此不会将签名者/证书信息注入到类的
ProtectionDomain,导致你调用的getSigners()、getCertificates()返回null。 - jarsigner提示的“jar verified”仅表示Jar签名与内容匹配(签名本身有效),但不代表证书被Java信任存储认可。
解决步骤
1. 将自签名证书导入Java信任存储
把你的自签名证书添加到Java系统信任存储(cacerts),或使用自定义信任存储:
- 先导出Jar中的证书:
# 查看Jar证书信息并导出 jarsigner -verify -verbose -certs your.jar > cert_info.txt # 根据输出中的证书别名,从密钥库导出证书 keytool -export -alias your-cert-alias -file your-cert.cer -keystore your-keystore.jks - 导入到系统信任存储(需管理员权限):
系统默认keytool -import -trustcacerts -alias your-cert-alias -file your-cert.cer -keystore $JAVA_HOME/lib/security/cacertscacerts密码为changeit。
2. 显式启用安全管理器(Java 17+需手动开启)
Java 17默认禁用安全管理器,若需类加载器自动关联签名信息,需显式开启并配置安全策略:
- 启动程序时添加参数:
java -Djava.security.manager=allow -Djava.security.policy=your-policy-file.policy YourMainClass - 在
your-policy-file.policy中配置签名权限:grant signedBy "your-cert-alias" { permission java.security.AllPermission; // 可根据需求设置更细粒度的权限 };
3. 直接解析Jar获取签名信息(绕过类加载器限制)
若不想修改信任存储或安全策略,可直接读取Jar文件提取签名与证书:
import java.io.IOException; import java.security.cert.Certificate; import java.util.jar.JarEntry; import java.util.jar.JarFile; public class JarSignatureParser { public static void main(String[] args) throws IOException { try (JarFile jarFile = new JarFile("your-target.jar")) { // 指定要检查的类文件路径 JarEntry classEntry = jarFile.getJarEntry("com/your/package/YourClass.class"); Certificate[] certs = classEntry.getCertificates(); if (certs != null) { for (Certificate cert : certs) { System.out.println("证书类型: " + cert.getType()); System.out.println("证书详情:\n" + cert.toString()); } } } } }
4. 确认签名算法兼容性
虽然jarsigner验证通过,仍可检查签名算法是否在Java 17允许范围内:
- 打开
$JAVA_HOME/conf/security/java.security文件,查看jdk.jar.disabledAlgorithms配置项,确保你使用的签名算法(如SHA256withRSA)不在禁用列表中。
内容的提问来源于stack exchange,提问作者Multicoder
相关产品推荐
相关产品推荐

