Https请求报错:unable to find valid certification path to requested target

SSL认证失败:

  • 报错信息如下:
sun.security.validator.ValidatorException:  
    PKIX path building failed:  
        sun.security.provider.certpath.SunCertPathBuilderException:  
            unable to find valid certification path to requested target
  • 问题发现环境:
    Java中使用了 HttpsURLConnection 去请求某资源,报此错误。
  • 错误原因:
    Java在访问SSL加密的网站时,需要从JDK的KeyStore 里面去查找相对应得可信证书,如果不能从默认或者指定的KeyStore 中找到可信证书,就会报这个错误。
    另外,Java所使用的证书仓库并不是Windows系统自带的证书管理。所以即使系统中包含此证书也不可以使用。

解决这个问题的办法有两种:
一是在发起https连接之前将服务器证书加到httpclient的信任证书列表中,这个相对来说比较复杂一些,很容易出错。
另一种办法是让httpclient信任所有的服务器证书,这种办法相对来说简单很多,但安全性则差一些,但在某些场合下有一定的应用场景。

  • 解决方式1:将所访问的SSL站点证书添加至JVM。
    echo -n |openssl s_client -connect 182.242.198.40:5000|sed -ne'/BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > xxxxx.cert
    此命令获取服务端证书链。
    keytool -importcert -alias 182.242.198.40-1 -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit -file xxxxx.cert
    此命令导入上述证书到JVM的证书库中。
    如果JAVA_HOME环境变量未设置,需要预先设置。 如:update-alternatives --list
    可以看到当前jdk的安装目录。如/usr/lib/java/jdk1.8.0_131
    则可以通过export JAVA_HOME=/usr/lib/java/jdk1.8.0_131来指定JAVA_HOME。
  • 解决方式2:忽略SSL认证。
    自定义javax.net.ssl.X509TrustManager实现类,在认证时直接忽略。
X509TrustManager x509m = new X509TrustManager() {
    
    
    //返回受信任的X509证书数组。
	@Override
	public X509Certificate[] getAcceptedIssuers() {
    
    
		return null;
	}
	
    //该方法检查服务器的证书,若不信任该证书同样抛出异常。通过自己实现该方法,可以使之信任我们指定的任何证书。
    //在实现该方法时,也可以简单的不做任何处理,即一个空的函数体,由于不会抛出异常,它就会信任任何证书。
	@Override
	public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    
    }
    
    //该方法检查客户端的证书,若不信任该证书则抛出异常。由于我们不需要对客户端进行认证,
    //因此我们只需要执行默认的信任管理器的这个方法。JSSE中,默认的信任管理器类为TrustManager。
    @Override
	public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    
    }
}

使用时:


HttpsURLConnection httpsConn = (HttpsURLConnection) realUrl.openConnection();
//Hostname认证直接通过
httpsConn.setHostnameVerifier(new HostnameVerifier() {
    
    
    public boolean verify(String hostname, SSLSession session) {
    
    
        return true;
    }
});
//ssl认证,UnTrustManager中的SSLContext设置了X509TrustManager的重写对象
httpsConn.setSSLSocketFactory(UnTrustManager.getSSLContext().getSocketFactory());

猜你喜欢

转载自blog.csdn.net/qq_37084673/article/details/108597947