报错 | PKIX path building failed: ...SunCertPathBuilderException:unable to find valid certification...


01 问题场景

在Java中访问不受信任的HTTPS网站时,会提示报错信息:

PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

翻译成中文是:

PKIX路径构建失败:sun.security.provider.certpath.SunCertPathBuilderException:无法找到请求目标的有效认证路径。

这是由于JVM (Java Virtual Machine) 默认信任证书不包含该目标网站的SSL证书,导致无法建立有效的信任链。

02 分析问题

JVM自己维护有一个默认的信任证书,是一个没有后缀名的文件,文件名为cacerts,位于java安装路径下,例如:

C:\Program Files\Java\jdk-17\lib\security\cacerts

当Java访问https的网站时,通常不会出现这一异常,但有的https网站,因为种种原因,存在证书不受信任的问题,使用浏览器访问会出现如下界面:

在这里插入图片描述
Java访问这种网站就会导致报错。

03 三种解决方案

经过我的一番搜寻,网上一般有解决方案:

  1. 信任所有SSL证书
    参考:https://developer.aliyun.com/article/812846
    这种方案不失为一种解决办法,但除了存在安全问题,还会对代码造成侵入,且在框架项目中不易集成。

  2. 将不信任的证书加入到JVM默认信任证书
    参考:https://www.cnblogs.com/qixing/p/11883494.html
    这种方案避免了代码入侵的问题,但想到要对java自带的默认文件动手动脚,且加入的还是不受信任的证书,多少有些不合适,而且加入后以后可能会忘记复原,或是要备份原始默认文件。

  3. 单独为不信任的网站生成证书并在项目中指定
    这也是本文使用的方案,避免了上面两个方案的问题。

04 解决步骤

4.1 获取目标网站的SSL证书

因为我是访问自己的网站,我作为站长,有自己的证书,就不涉及获取目标网站证书的问题,如果需要获取,也不困难,直接在浏览器网页左上角点击图标,进行导出即可(可自行百度),导出后通常为.crt.pem文件。

4.2 创建一个Java信任库

创建一个Java信任库(Truststore),并将目标网站的SSL证书导入其中。使用java自带的keytool命令行工具来完成此操作。在cmd中使用命令:

keytool -import -keystore <信任库文件路径> -storepass <密码> -alias alias_for_certificate -file <证书文件路径>

该命令由4个部分组成:
keytool -import 用于导入的命令
-keystore <信任库文件路径> 希望生成的信任库文件,例如路径可以写:C:\Users\abc\Desktop\truststore.jks
-storepass <密码> 设置一个信任库密码
-alias alias_for_certificate -file <证书文件路径> 指定要导入的证书文件,例如可以写:C:\Users\abc\Desktop\cert.pem

4.3 告知JVM使用信任库

在你的Java应用程序中,告知JVM使用你刚刚创建的信任库。使JVM在运行时加载该信任库。
通过设置以下系统属性来实现:

System.setProperty("javax.net.ssl.trustStore", "<信任库文件路径>");	// 刚才填写的路径
System.setProperty("javax.net.ssl.trustStorePassword", "<密码>");	// 刚才填写的密码

这样问题就得到解决了!

05 补充

5.1 命令行提示没有keytool的解决

通常是因为jdk没有加入环境变量造成的,可以加入环境变量再试,或者直接cd到keytool所在的路径执行命令,例如我的keytool工具存放位置在:C:\Program Files\Java\jdk-17\bin目录下。

5.2 SpringBoot项目中如何指定信任库

将上面的两行代码放到SpringApplication.run()所在位置即可。示例:

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
        // 代码放到这里 可以使用相对路径
        System.setProperty("javax.net.ssl.trustStore", "C:\\Users\\truststore.jks");
        System.setProperty("javax.net.ssl.trustStorePassword", "123456");
    }
}
  • 13
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿林仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值