JDK低版本导致SunCertPathBuilderException unable to find valid certification path to requested target 证书异常

系统在调用外部HTTPS接口时遇到SSLHandshakeException,原因是证书验证失败。尽管curl测试返回OK,但问题可能出在JDK版本过低,无法识别新证书。升级JDK到最新子版本通常可以解决此类问题。其他可能原因包括服务器证书过新或过旧,以及证书内容校验失败,如缺少可信根证书或证书过期。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景:
系统调用外部Https接口,外部接口提供方更换了网站证书,导致我们(https客户端)报错

堆栈信息如下(抹去了业务代码的堆栈)


javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) ~[?:1.8.0_45]
	at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1937) ~[?:1.8.0_45]
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302) ~[?:1.8.0_45]
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296) ~[?:1.8.0_45]
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1478) ~[?:1.8.0_45]
	at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:212) ~[?:1.8.0_45]
	at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979) ~[?:1.8.0_45]
	at sun.security.ssl.Handshaker.process_record(Handshaker.java:914) ~[?:1.8.0_45]
	at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1050) ~[?:1.8.0_45]
	at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1363) ~[?:1.8.0_45]
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1391) ~[?:1.8.0_45]
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1375) ~[?:1.8.0_45]
	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:394) ~[httpclient-4.5.2.jar!/:4.5.2]
	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:353) ~[httpclient-4.5.2.jar!/:4.5.2]
	at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:141) ~[httpclient-4.5.2.jar!/:4.5.2]
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353) ~[httpclient-4.5.2.jar!/:4.5.2]
	at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380) ~[httpclient-4.5.2.jar!/:4.5.2]
	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236) ~[httpclient-4.5.2.jar!/:4.5.2]
	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184) ~[httpclient-4.5.2.jar!/:4.5.2]
	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88) ~[httpclient-4.5.2.jar!/:4.5.2]
	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) ~[httpclient-4.5.2.jar!/:4.5.2]
	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184) ~[httpclient-4.5.2.jar!/:4.5.2]
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82) ~[httpclient-4.5.2.jar!/:4.5.2]
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107) ~[httpclient-4.5.2.jar!/:4.5.2]
	//省去业务代码堆栈
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.12.RELEASE.jar!/:4.3.12.RELEASE]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738) ~[spring-aop-4.3.12.RELEASE.jar!/:4.3.12.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.12.RELEASE.jar!/:4.3.12.RELEASE]
	at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.3.12.RELEASE.jar!/:4.3.12.RELEASE]
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) ~[spring-tx-4.3.12.RELEASE.jar!/:4.3.12.RELEASE]
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.12.RELEASE.jar!/:4.3.12.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.12.RELEASE.jar!/:4.3.12.RELEASE]
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-4.3.12.RELEASE.jar!/:4.3.12.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.12.RELEASE.jar!/:4.3.12.RELEASE]
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673) ~[spring-aop-4.3.12.RELEASE.jar!/:4.3.12.RELEASE]
	at com.sankuai.zc.open.inform.service.impl.TradeOrderStatusHTTPInformServiceImpl$$EnhancerBySpringCGLIB$$f64e4cff.inform2Biz(<generated>) ~[open-inform-0.0.1-SNAPSHOT.jar!/:0.0.1-SNAPSHOT]
	at com.sankuai.zc.open.inform.service.dispatcher.InformDispatcherService.inform(InformDispatcherService.java:58) ~[open-inform-0.0.1-SNAPSHOT.jar!/:0.0.1-SNAPSHOT]
	at com.sankuai.zc.open.inform.service.mqService.DelayMqListener.callback(DelayMqListener.java:103) ~[open-inform-0.0.1-SNAPSHOT.jar!/:0.0.1-SNAPSHOT]
	at com.sankuai.zc.open.inform.notify.InformAbstractService.doDelayMqCallBack(InformAbstractService.java:53) ~[open-inform-0.0.1-SNAPSHOT.jar!/:0.0.1-SNAPSHOT]
	at com.sankuai.zc.open.inform.service.mqService.DelayMqListener.lambda$recvMessage$7(DelayMqListener.java:84) ~[open-inform-0.0.1-SNAPSHOT.jar!/:0.0.1-SNAPSHOT]
	at com.sankuai.zc.open.inform.service.mqService.DelayMqListener$$Lambda$50/106665305.run(Unknown Source) ~[?:?]
	at com.meituan.mtrace.thread.TraceRunnable.run(TraceRunnable.java:30) ~[mtrace-agent-1.1.24.1.jar!/:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[?:1.8.0_45]
	at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[?:1.8.0_45]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[?:1.8.0_45]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) ~[?:1.8.0_45]
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-all-4.1.31.Final.jar!/:4.1.31.Final]
	at java.lang.Thread.run(Thread.java:745) ~[?:1.8.0_45]
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387) ~[?:1.8.0_45]
	at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292) ~[?:1.8.0_45]
	at sun.security.validator.Validator.validate(Validator.java:260) ~[?:1.8.0_45]
	at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324) ~[?:1.8.0_45]
	at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229) ~[?:1.8.0_45]
	at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124) ~[?:1.8.0_45]
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1460) ~[?:1.8.0_45]
	... 46 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:145) ~[?:1.8.0_45]
	at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:131) ~[?:1.8.0_45]
	at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280) ~[?:1.8.0_45]
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382) ~[?:1.8.0_45]
	at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292) ~[?:1.8.0_45]
	at sun.security.validator.Validator.validate(Validator.java:260) ~[?:1.8.0_45]
	at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324) ~[?:1.8.0_45]
	at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229) ~[?:1.8.0_45]
	at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124) ~[?:1.8.0_45]
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1460) ~[?:1.8.0_45]
	... 46 more

首先curl -v分别在自己本地和服务端上访问该域名,都返回ok,说明不是证书问题。与SRE开会沟通,SRE提起说之前处理过类似的问题,原因是因为jdk8的版本过低,升级jdk8的子版本,问题解决,

总结:unable to find valid certification path to requested target一般是如下原因导致
1.服务器证书过新,jdk识别不了:比如新增的加密算法、不同的证书格式等,会直接阻塞。 需要升级jdk
2.服务器证书过旧,jdk识别不了,但是jdk一般会向下兼容
3.证书内容校验失败:比如无可信的根证书、证书已过期等。但通常都可以不阻塞请求(提示不安全)

原因3比较好排除,curl -v测试一下或者拷贝下来网站证书在线校验一下即可
如何查看网站证书:https://blog.youkuaiyun.com/ever_peng/article/details/93720072
 

### 解决 SunCertPathBuilderException 无法找到有效认证路径 当遇到 `sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target` 错误时,这通常意味着 Java 运行环境中缺少必要的 SSL 证书或中间证书[^2]。 #### 方法一:安装缺失的证书到 JVM 的信任库 为了使 Maven 能够成功连接远程仓库并下载依赖项,可以手动将所需的 CA 证书导入到 JDK/JRE 自带的信任存储文件 (`cacerts`) 中: 1. 获取目标服务器的根证书和任何必需的中级证书; 2. 使用 keytool 工具将其添加至 cacerts 文件中; ```bash keytool -importcert -alias exampleAliasName \ -file /path/to/certificate.crt \ -keystore $JAVA_HOME/jre/lib/security/cacerts \ -storepass changeit ``` 此命令会提示确认是否要信任该证书,在输入 yes 后完成操作即可[^1]。 #### 方法二:配置 Maven 忽略 SSL 验证(不推荐用于生产环境) 对于开发测试阶段而言,可以通过设置系统属性来绕过 SSL 握手过程中的主机名验证以及关闭所有 HTTPS 请求的安全检查。但这并不适用于正式部署场景因为这样做会使应用程序暴露于潜在风险之下。 编辑 settings.xml 或者 pom.xml 添加如下配置片段: ```xml <profiles> <profile> <id>allow-all</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <!-- 关闭Maven Wagon组件对HTTPS请求做SSL握手 --> <maven.wagon.http.ssl.insecure>true</maven.wagon.http.ssl.insecure> <maven.wagon.http.ssl.allowall>true</maven.wagon.http.ssl.allowall> <maven.wagon.http.ssl.ignore.validity.dates>true</maven.wagon.http.ssl.ignore.validity.dates> </properties> </profile> </profiles> ``` 这种方法虽然简单快捷但是安全性较差因此仅限于本地调试使用[^3]。 #### 方法三:调整项目结构修正 parent.relativePath 设置不当引起的问题 如果同时还存在 `'parent.relativePath' points at wrong local POM` 提示,则可能是由于项目的父POM定义有误造成的。应确保子模块能够正确定位其对应的父级工程位置从而顺利完成构建流程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值