服务调用HTTPS接口: PKIX路径构建失败异常
在现代的网络通信中,HTTPS的使用已经非常普遍。与HTTP相比,HTTPS通过使用SSL/TLS协议对通信进行加密,确保数据的安全性和完整性。然而,有时候在通过Java代码调用HTTPS接口时,可能会遇到javax.net.ssl.SSLHandshakeException: PKIX path building failed
异常。本文将介绍这个异常的原因和解决方法。
异常原因
PKIX(Public Key Infrastructure X.509)是一种公钥基础设施标准,用于验证证书链的合法性。在与HTTPS服务器建立连接时,Java代码会执行证书链的验证过程。如果服务器的证书链中的任何一个证书无法通过验证,就会抛出javax.net.ssl.SSLHandshakeException: PKIX path building failed
异常。
这个异常通常有以下几种原因:
- 服务器的证书链中存在过期或无效的证书。
- 服务器的证书链中的证书在本地信任库中找不到。
- 本地信任库中的证书已过期或失效。
解决方法
针对上述的异常原因,我们可以采取以下几种解决方法。
1. 更新本地信任库
我们可以通过更新本地信任库中的证书,来确保服务器证书链中的证书可以正确地进行验证。
首先,我们需要获取服务器证书链中的证书,可以使用以下代码获得服务器证书的PEM格式字符串:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
public class RetrieveCert {
public static void main(String[] args) throws IOException, CertificateException {
String url = "
URL serverUrl = new URL(url);
Certificate[] serverCerts = retrieveCertificates(serverUrl);
// 打印证书信息
for (Certificate cert : serverCerts) {
System.out.println(cert.toString());
}
}
private static Certificate[] retrieveCertificates(URL url) throws IOException, CertificateException {
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
try (BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()))) {
String inputLine;
while ((inputLine = in.readLine()) != null) {
if (inputLine.contains("BEGIN CERTIFICATE") && !inputLine.contains("END CERTIFICATE")) {
StringBuilder certBuffer = new StringBuilder();
certBuffer.append(inputLine).append("\n");
// 读取整个证书
while ((inputLine = in.readLine()) != null) {
certBuffer.append(inputLine).append("\n");
if (inputLine.contains("END CERTIFICATE")) {
break;
}
}
// 解析证书
Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(
certBuffer.toString().getBytes()));
// 添加到证书链中
// ...
}
}
}
// 返回证书链
// ...
}
}
在上述代码中,我们通过URL
类从HTTPS链接获取服务器返回的数据,并从中提取证书。然后,我们将证书添加到证书链中进行验证。具体的证书添加方式根据不同的请求库和框架而定。
2. 导入服务器证书到本地信任库
如果服务器的证书链中的证书无法通过验证,我们可以将服务器的证书手动导入本地信任库中,以确保Java代码可以正确验证服务器证书。
首先,我们需要获取服务器的证书,可以使用以下命令从HTTPS服务器获取证书:
openssl s_client -showcerts -servername example.com -connect example.com:443 </dev/null
然后,我们将输出的证书保存为一个PEM格式的文件,例如example.crt
。
接下来,我们可以使用keytool
命令将证书导入到本地信任库中:
keytool -import -trustcacerts -alias example -file example.crt -keystore cacerts
cacerts
是Java默认的信任库文件,通常位于JDK安装目录的lib/security
目录下。
3. 忽略证书验证
在某些情况下,我们可能希望暂时忽略对服务器证书的验证。这通常用于测试或开发环境中