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();

        }

    }
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed 是由于SSL握手过程中发生了异常引起的。具体错误是PKIX path building failed,这意味着在验证服务器端证书时出现了问题。这个错误通常是由于缺少信任的证书证书链不完整导致的。可能的原因有以下几种: 1. 信任的证书列表不完整或不正确。在SSL握手过程中,需要验证服务器端的证书是否被信任。如果没有正确配置信任的证书列表,就会导致PKIX path building failed错误。 2. 服务器端的证书链不完整或不正确。证书链是由多个证书组成的,其中包括服务器端证书和中间证书。如果服务器端的证书链不完整或不正确,就无法构建验证路径,从而导致PKIX path building failed错误。 解决这个问题的方法有以下几种: 1. 检查信任的证书列表。确保信任的证书列表包含了服务器端证书所使用的根证书或中间证书。可以使用keytool命令来查看信任的证书列表,比如:keytool -list -keystore cacerts。 2. 确认服务器端证书链的完整性。可以使用SSL证书工具来检查服务器端证书链是否完整。如果发现缺少中间证书,可以从证书颁发机构的网站下载并添加到信任的证书列表中。 3. 检查服务器端证书的有效性。确保服务器端证书的有效期和颁发机构都是正确的。如果证书已过期或由非信任的颁发机构签发,就需要更换有效的证书。 总之,PKIX path building failed错误通常是由于SSL证书验证过程中出现问题导致的。通过检查信任的证书列表、确认证书链的完整性和检查证书的有效性,可以解决这个问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值