SSL 跳过证书验证 javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.cer

最开始网站是 http 的,后来升级成了 https 。内网环境是自己签发的证书,今天准备访问的时候报错了。原来已经加了跳过证书验证的代码了,还是报错了。

1. 为什么原来的设置不起作用

原来的设置如下,是在 spring boot 的启动类里设置了一段静态代码,跳过了证书验证:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

@SpringBootApplication
public class MyApplication {
    static {
        try {
            SSLContext sslc;
            sslc = SSLContext.getInstance("TLS");
            TrustManager[] trustManagerArray = {new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {

                }

                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {

                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[0];
                }
            }};
            sslc.init(null, trustManagerArray, null);
            HttpsURLConnection.setDefaultSSLSocketFactory(sslc.getSocketFactory());
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String s, SSLSession sslSession) {
                    return true;
                }
            });
        } catch (Exception e) {
            throw new IllegalArgumentException("证书校验异常!");
        }
    }


    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

}

分析了下,原来应该是针对的:

java.net.HttpURLConnection

而我今天调用的是 apache 的 httpClient ,所以原来的设置就无效了。

2. 今天访问网络的代码

就是利用 http client 简单的访问了一个 url ,http client 版本是 : org.apache.httpcomponents:httpclient:jar:4.5.6 。

package com.huitongjy.user.support.util;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;

/**
 * @author shifengqiang 2022/3/15 6:03 PM
 */
public class TestHttps {
    public static void main(String[] args) {
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        try {
            String url = "https://xxxxxxx";
            HttpGet get = new HttpGet(url);

            HttpResponse response = httpClient.execute(get);
            String result = EntityUtils.toString(response.getEntity(), "utf-8");
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();

        }

    }
}

结果报错了,异常栈如下:

javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.ssl.Alert.createSSLException(Alert.java:131)
	at sun.security.ssl.TransportContext.fatal(TransportContext.java:327)
	at sun.security.ssl.TransportContext.fatal(TransportContext.java:270)
	at sun.security.ssl.TransportContext.fatal(TransportContext.java:265)
	at sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:646)
	at sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:465)
	at sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:361)
	at sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:376)
	at sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:451)
	at sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:428)
	at sun.security.ssl.TransportContext.dispatch(TransportContext.java:184)
	at sun.security.ssl.SSLTransport.decode(SSLTransport.java:154)
	at sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1198)
	at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1107)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:400)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:372)
	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:394)
	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:353)
	at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:134)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353)
	at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380)
	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)
	at com.huitongjy.user.support.util.TestHttps.main(TestHttps.java:19)
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:439)
	at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:306)
	at sun.security.validator.Validator.validate(Validator.java:271)
	at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:312)
	at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:221)
	at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:128)
	at sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:630)
	... 24 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:141)
	at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
	at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:434)
	... 30 more

根据报错信息,查了下是在

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.apache.http.ssl;

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import org.apache.http.annotation.Immutable;

@Immutable
public class SSLContexts {
    public SSLContexts() {
    }

    public static SSLContext createDefault() throws SSLInitializationException {
        try {
            SSLContext sslcontext = SSLContext.getInstance("TLS");
            sslcontext.init((KeyManager[])null, (TrustManager[])null, (SecureRandom)null);
            return sslcontext;
        } catch (NoSuchAlgorithmException var1) {
            throw new SSLInitializationException(var1.getMessage(), var1);
        } catch (KeyManagementException var2) {
            throw new SSLInitializationException(var2.getMessage(), var2);
        }
    }

    public static SSLContext createSystemDefault() throws SSLInitializationException {
        try {
            return SSLContext.getDefault();
        } catch (NoSuchAlgorithmException var1) {
            return createDefault();
        }
    }

    public static SSLContextBuilder custom() {
        return SSLContextBuilder.create();
    }
}

3. 修复过程

原来 sslContext 自己又重新 new 了,全部初始化为空了。所以之前静态代码设置的 sslContext 自然就不起作用了。

又查了下代码,在:
HttpClientBuilder 里可以设置 sslContext 。
对原来的代码简单的修改了一下就可以了:

package com.huitongjy.user.support.util;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;

/**
 * @author shifengqiang 2022/3/15 6:03 PM
 */
public class TestHttps {
    private static SSLContext ctx;
    static {
        try {
            ctx = SSLContext.getInstance("TLS");
            X509TrustManager tm = new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                public void checkClientTrusted(X509Certificate[] arg0,
                    String arg1) throws CertificateException {
                }

                public void checkServerTrusted(X509Certificate[] arg0,
                    String arg1) throws CertificateException {
                }
            };
            ctx.init(null, new TrustManager[] { tm }, null);
        } catch (Exception e) {
            System.out.println(e);
        }
    }
    
    public static void main(String[] args) {
        // 在这儿加了 setSSLContext(ctx)
        CloseableHttpClient httpClient = HttpClientBuilder.create().setSSLContext(ctx).build();
        try {
            String url = "https://usersystem-new.testd.huitong.com/ruok";
            HttpGet get = new HttpGet(url);

            HttpResponse response = httpClient.execute(get);
            String result = EntityUtils.toString(response.getEntity(), "utf-8");
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();

        }

    }
}

你可能感兴趣的:(ssl,https,java)