Java调用HTTPS接口出现sun.security.validator.ValidatorException: PKIX path valida异常解析及解决方案

介绍

在Java开发中,我们经常会使用HTTP协议调用远程接口。而当我们需要调用HTTPS接口时,会遇到sun.security.validator.ValidatorException: PKIX path valida异常。本文将从原理、出现原因和解决方案三个方面来进行详细讲解。

问题原因

在使用Java调用HTTPS接口时,会涉及到证书的验证。当Java客户端发起HTTPS请求时,会验证远程服务器返回的证书是否可信。如果证书不可信,就会抛出sun.security.validator.ValidatorException: PKIX path valida异常。

这个异常主要有以下几个常见的原因:

  1. 服务器证书不受信任:Java默认信任的证书存储在JDK的cacerts文件中,如果服务器证书不在信任列表中,就会抛出异常。

  2. 证书链不完整:服务器返回的证书链可能不完整,缺少中间证书。而Java为了验证证书的合法性,需要完整的证书链。

  3. 证书过期:如果服务器的证书已经过期,Java也会认为证书不可信。

解决方案

针对上述问题,我们可以采取以下几种解决方案。

方案一:信任所有证书

我们可以通过创建一个信任所有证书的TrustManager来解决该问题。代码示例如下:

import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import javax.net.ssl.*;

public class TrustAllManager implements X509TrustManager {
    public void checkClientTrusted(X509Certificate[] certs, String authType) {}
    public void checkServerTrusted(X509Certificate[] certs, String authType) {}
    public X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[0];
    }
}

// 在调用HTTPS接口前,添加以下代码
TrustManager[] trustAllCerts = new TrustManager[] { new TrustAllManager() };
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());

该方案虽然解决了证书验证的问题,但是也存在一定的安全风险,因为它会信任所有的证书,包括无效或不受信任的证书。

方案二:添加缺失的中间证书

在服务器返回的证书链中,可能缺少一些中间证书。我们可以通过将缺失的中间证书添加到信任列表中来解决该问题。

  1. 查找缺失的中间证书 可以使用在线工具或通过命令行工具(如openssl)来查找缺失的中间证书。一般来说,服务器的SSL证书提供商会有相关的中间证书下载页面。

  2. 下载中间证书 下载所有缺失的中间证书,保存为.cer.crt格式的文件。

  3. 导入中间证书 将下载的中间证书导入到Java的cacerts文件中:

    keytool -import -alias intermediate -file intermediate.crt -keystore cacerts
    

    其中,intermediate.crt是下载的中间证书文件。

  4. 使用SSL证书验证 在调用HTTPS接口前,添加以下代码,告诉Java使用导入的证书进行验证:

    System.setProperty("javax.net.ssl.trustStore", "path/to/cacerts");
    

    其中,path/to/cacertscacerts文件的路径。

方案三:使用自定义证书

如果你有自己的证书,可以通过以下方式来解决该问题。

  1. 导入自定义证书 将自定义证书导入到Java的cacerts文件中:

    keytool -import -alias custom -file custom.crt -keystore cacerts
    

    其中,custom.crt是自定义证书文件。

  2. 使用自定义证书验证 在调用HTTPS接口前,添加以下代码,告诉Java使用自定义证书进行验证:

    System.setProperty("