HTTP Client CFCA SSL证书授信问题处理

目录

HTTP Client CFCA SSL证书授信问题处理

问题描述

调研

解决方案

方案1: 将根证书或当前证书导入到JDK的授信库

方案2: HTTP Client 忽略所有SSL证书的验证

方案3: HTTP Client 只忽略CFCA签发的SSL证书的验证


HTTP Client CFCA SSL证书授信问题处理

问题描述

通过HTTP Client 访问CFCA 签发的SSL证书的域名时出错,异常信息:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at java.base/sun.security.ssl.Alerts.getSSLException(Alerts.java:198)
    at java.base/sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1969)
    at java.base/sun.security.ssl.Handshaker.fatalSE(Handshaker.java:345)
    at java.base/sun.security.ssl.Handshaker.fatalSE(Handshaker.java:339)
    at java.base/sun.security.ssl.ClientHandshaker.checkServerCerts(ClientHandshaker.java:1968)
    at java.base/sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1777)
    at java.base/sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:264)
    at java.base/sun.security.ssl.Handshaker.processLoop(Handshaker.java:1092)
    at java.base/sun.security.ssl.Handshaker.processRecord(Handshaker.java:1026)
    at java.base/sun.security.ssl.SSLSocketImpl.processInputRecord(SSLSocketImpl.java:1137)
    at java.base/sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1074)
    at java.base/sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973)
    at java.base/sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1402)
    at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1429)
    at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:396)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:355)
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:373)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:381)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:237)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)

证书信息:

HTTP Client CFCA SSL证书授信问题处理_第1张图片

调研

因为JDK 没有把CFCA的根证书加入的授信的库列表里,但市面上主流的浏览器基本都加入,因此导致浏览器可以正常方法,但通过HTTP Client 访问就会提示SSL证书检查不通过。

解决方案

方案1: 将根证书或当前证书导入到JDK的授信库

该方案实现难度较大,需要在所有代码执行的地方都执行导入的动作

方案2: HTTP Client 忽略所有SSL证书的验证

构建一个信任所有证书的SSLContext

public static SSLContext getSSLIgnoreContext(){
    try {
        return SSLContexts.custom().loadTrustMaterial(new TrustAllStrategy()).build();
    } catch (NoSuchAlgorithmException e) {
        log.warn(e);
    } catch (KeyManagementException e) {
        log.warn(e);
    } catch (KeyStoreException e) {
        log.warn(e);
    }
    return null;
}

创建HTTP Client,指定SSLContext

public static CloseableHttpClient getSSLIgnoreCheckHttpClient(){
    return HttpClientBuilder.create()
        .setSSLContext(getSSLIgnoreContext())
        .build();
}
该方案的风险较大,会导致所有SSL证书都不验证。

方案3: HTTP Client 只忽略CFCA签发的SSL证书的验证

创建一个CFCA免验证的授信策略类TrustStrategy

public class CFCATrustStrategy implements TrustStrategy {

    /**
     * Determines whether the certificate chain can be trusted without consulting the trust manager
     * configured in the actual SSL context. This method can be used to override the standard JSSE
     * certificate verification process.
     * 

* Please note that, if this method returns {@code false}, the trust manager configured * in the actual SSL context can still clear the certificate as trusted. * * @param chain the peer certificate chain * @param authType the authentication type based on the client certificate * @return {@code true} if the certificate can be trusted without verification by * the trust manager, {@code false} otherwise. * @throws CertificateException thrown if the certificate is not trusted or invalid. */ @Override public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { if(chain!=null && chain.length > 0){ for(X509Certificate certificate:chain){ if("CN=CFCA EV ROOT, O=China Financial Certification Authority, C=CN".equals(certificate.getSubjectDN().getName())){ return true; } } } return false; } }

构建一个只忽略CFCA签发的证书的SSLContext

public static SSLContext getCFCASSLIgnoreContext(){
    try {
        return SSLContexts.custom().loadTrustMaterial(new CFCATrustStrategy()).build();
    } catch (NoSuchAlgorithmException e) {
        log.warn(e);
    } catch (KeyManagementException e) {
        log.warn(e);
    } catch (KeyStoreException e) {
        log.warn(e);
    }
    return null;
}

创建HTTP Client,指定SSLContext

public static CloseableHttpClient getSSLIgnoreCheckHttpClient(){
    return HttpClientBuilder.create()
        .setSSLContext(getSSLIgnoreContext())
        .build();
}
该方案的风险较小,推荐使用。

你可能感兴趣的:(我的分享,ssl,http,https,java)