Java 使用Apache Async HttpClient 4.0.x时忽略HTTPS连接上的错误证书

Java 使用Apache Async HttpClient 4.0.x时忽略HTTPS连接上的错误证书,java,apache,ssl,asynchronous,apache-httpclient-4.x,Java,Apache,Ssl,Asynchronous,Apache Httpclient 4.x,我正在使用异步Apache HttpClient(CloseableHttpAsyncClient)连接到服务器,但遇到以下异常: javax.net.ssl.SSLHandshakeException: General SSLEngine problem at org.apache.http.concurrent.BasicFuture.failed(BasicFuture.java:130) at org.apache.http.impl.nio.client.Default

我正在使用异步Apache HttpClient(CloseableHttpAsyncClient)连接到服务器,但遇到以下异常:

javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    at org.apache.http.concurrent.BasicFuture.failed(BasicFuture.java:130)
    at org.apache.http.impl.nio.client.DefaultClientExchangeHandlerImpl.failed(DefaultClientExchangeHandlerImpl.java:258)
    at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.exception(HttpAsyncRequestExecutor.java:123)
    at org.apache.http.impl.nio.client.InternalIODispatch.onException(InternalIODispatch.java:68)
    at org.apache.http.impl.nio.client.InternalIODispatch.onException(InternalIODispatch.java:37)
    at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:124)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:159)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:338)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:316)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:277)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:105)
    at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:584)
    at java.lang.Thread.run(Thread.java:695)
Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    at com.sun.net.ssl.internal.ssl.Handshaker.checkThrown(Handshaker.java:1015)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.checkTaskThrown(SSLEngineImpl.java:485)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.writeAppRecord(SSLEngineImpl.java:1108)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.wrap(SSLEngineImpl.java:1080)
    at javax.net.ssl.SSLEngine.wrap(SSLEngine.java:452)
    at org.apache.http.nio.reactor.ssl.SSLIOSession.doWrap(SSLIOSession.java:220)
    at org.apache.http.nio.reactor.ssl.SSLIOSession.doHandshake(SSLIOSession.java:254)
    at org.apache.http.nio.reactor.ssl.SSLIOSession.isAppInputReady(SSLIOSession.java:391)
    at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:119)
    ... 7 more
Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1508)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:243)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:235)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1209)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:135)
    at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593)
    at com.sun.net.ssl.internal.ssl.Handshaker$1.run(Handshaker.java:533)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.net.ssl.internal.ssl.Handshaker$DelegatedTask.run(Handshaker.java:952)
    at org.apache.http.nio.reactor.ssl.SSLIOSession.doRunTask(SSLIOSession.java:238)
    at org.apache.http.nio.reactor.ssl.SSLIOSession.doHandshake(SSLIOSession.java:276)
    ... 9 more
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:323)
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:217)
    at sun.security.validator.Validator.validate(Validator.java:218)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:126)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:209)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:249)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1188)
    ... 16 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:174)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:318)
    ... 22 more
由于这是一个测试服务器,我只希望CloseableHttpAsyncClient忽略所有SSL错误。我知道如何使用HttpClient的非异步版本来实现这一点(例如,已经回答了这个问题),但我无法使用异步版本来实现这一点

我尝试了以下方法:

TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
    public boolean isTrusted(X509Certificate[] certificate, String authType) {
        return true;
    }
};

SSLContext sslContext = null;
try {
    sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
} catch (Exception e) {
    // Handle error
}

CloseableHttpAsyncClient client = HttpAsyncClients.custom()
        .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
        .setSSLContext(sslContext).build();
TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
    public boolean isTrusted(X509Certificate[] certificate, String authType) {
        return true;
    }
};

SSLContext sslContext = null;
try {
    sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
} catch (Exception e) {
    // Handle error
}

CloseableHttpAsyncClient client = HttpAsyncClients.custom()
        .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
        .setSSLContext(sslContext).build();

但它不起作用。有人知道如何解决这个问题吗?

我怀疑这个问题与主机名验证无关。SSL握手很可能在SSL会话协商之前就失败了。此类故障可能有多种原因,最有可能的原因是SSL协议版本不匹配。您应该在激活SSL调试日志的情况下运行应用程序(使用
-Djavax.net.debug=all
系统属性),并分析日志输出

我怀疑此问题与主机名验证无关。SSL握手很可能在SSL会话协商之前就失败了。此类故障可能有多种原因,最有可能的原因是SSL协议版本不匹配。您应该在激活SSL调试日志的情况下运行应用程序(使用
-Djavax.net.debug=all
系统属性),并分析日志输出

实际上我在问题中提供的代码是有效的。问题是,我当时正在使用(在引擎盖下使用Apache HttpClient),并将其配置为:

Unirest.setAsyncHttpClient(createHttpAsyncClient(CONNECTION_TIMEOUT, SOCKET_TIMEOUT));
Unirest.setTimeouts(CONNECTION_TIMEOUT, SOCKET_TIMEOUT);
问题是,“设置超时”覆盖了我在
createHttpAsyncClient
中所做的配置,没有任何指示。改为

Unirest.setTimeouts(CONNECTION_TIMEOUT, SOCKET_TIMEOUT);
Unirest.setAsyncHttpClient(createHttpAsyncClient(CONNECTION_TIMEOUT, SOCKET_TIMEOUT));
让一切顺利

因此,如果其他人在普通异步Apache HTTPClient中有相同的问题,那么使其信任所有证书的代码如下:

TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
    public boolean isTrusted(X509Certificate[] certificate, String authType) {
        return true;
    }
};

SSLContext sslContext = null;
try {
    sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
} catch (Exception e) {
    // Handle error
}

CloseableHttpAsyncClient client = HttpAsyncClients.custom()
        .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
        .setSSLContext(sslContext).build();
TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
    public boolean isTrusted(X509Certificate[] certificate, String authType) {
        return true;
    }
};

SSLContext sslContext = null;
try {
    sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
} catch (Exception e) {
    // Handle error
}

CloseableHttpAsyncClient client = HttpAsyncClients.custom()
        .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
        .setSSLContext(sslContext).build();

实际上,我在问题中提供的代码是有效的。问题是,我当时正在使用(在引擎盖下使用Apache HttpClient),并将其配置为:

Unirest.setAsyncHttpClient(createHttpAsyncClient(CONNECTION_TIMEOUT, SOCKET_TIMEOUT));
Unirest.setTimeouts(CONNECTION_TIMEOUT, SOCKET_TIMEOUT);
问题是,“设置超时”覆盖了我在
createHttpAsyncClient
中所做的配置,没有任何指示。改为

Unirest.setTimeouts(CONNECTION_TIMEOUT, SOCKET_TIMEOUT);
Unirest.setAsyncHttpClient(createHttpAsyncClient(CONNECTION_TIMEOUT, SOCKET_TIMEOUT));
让一切顺利

因此,如果其他人对纯异步Apache HTTPClient有相同的问题,那么使其信任所有证书的代码如下:

TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
    public boolean isTrusted(X509Certificate[] certificate, String authType) {
        return true;
    }
};

SSLContext sslContext = null;
try {
    sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
} catch (Exception e) {
    // Handle error
}

CloseableHttpAsyncClient client = HttpAsyncClients.custom()
        .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
        .setSSLContext(sslContext).build();
TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
    public boolean isTrusted(X509Certificate[] certificate, String authType) {
        return true;
    }
};

SSLContext sslContext = null;
try {
    sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
} catch (Exception e) {
    // Handle error
}

CloseableHttpAsyncClient client = HttpAsyncClients.custom()
        .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
        .setSSLContext(sslContext).build();

如果正在测试,您可以使用可用的类绕过证书。不幸的是,它使用了不推荐使用的http客户端类,我似乎无法将其挂接到HttpAsyncClientBuilder。如果正在测试,您可以绕过证书,不幸的是,通过使用可用的类,它使用了不推荐使用的http客户机类,我似乎无法将其连接到HttpAsyncClientBuilder中。