问题
I am trying to accept all certificates, and/or accept self-signed certificates using Apache HTTPClient version 4.5 (tutorial link here)
I've been going through solutions to this problem from a bunch of posts on SO. So far none of them have worked.
I keep getting this error: Error while trying to execute request. javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
Apache Docs:
- Apache v4.5 tutorial
- SSL/TLS customization
- Apache has a guide for version 3, but not version 4.
Related StackOverflow Questions - Here's some links of the solutions I've tried:
- Ignoring SSL certificate in Apache HttpClient 4.3
- How to ignore SSL certificate errors in Apache HttpClient 4.0
- Ignore SSL Certificate Errors with Java
- Need to trust all the certificates during the development using Spring
- How to handle invalid SSL certificates with Apache HttpClient?
Note that in all these examples I am also passing a cookie store and a proxy credentials provider that I defined earlier. These are working, I'm just trying to add SSL support.
Try #1
Create my own ssl context with SSLContextBuilder
and trust all self signed strategies with TrustSelfSignedStrategy
.
SSLContextBuilder sshbuilder = new SSLContextBuilder();
sshbuilder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sshbuilder.build());
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCredentialsProvider(credsProvider)
.setDefaultCookieStore(cookieStore)
.setSSLSocketFactory(sslsf)
.build();
RESULT: Didn't work. Got Error while trying to execute request. javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
Try #2
Same as above, but add a PoolingHttpClientConnectionManager
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(),SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", new PlainConnectionSocketFactory())
.register("https", sslsf)
.build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
cm.setMaxTotal(2000);//max connection
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCredentialsProvider(credsProvider)
.setDefaultCookieStore(cookieStore)
.setSSLSocketFactory(sslsf)
.setConnectionManager(cm)
.build();
RESULT: Didn't work. Got Error while trying to execute request. javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
Try #3
Simply accept ALL certificates by overriding the TrustStrategy
(this is not recommended)
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
});
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(),
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCredentialsProvider(credsProvider)
.setDefaultCookieStore(cookieStore)
.setSSLSocketFactory(sslsf)
.build();
RESULT: Didn't work. Got Error while trying to execute request. javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
Try #4
I found something useful from this answer:
As of version 4.5 HttpClient disables SSLv3 protocol version by default
Here's the solution he gave:
SSLContext sslcontext = SSLContexts.createSystemDefault();
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
sslcontext, new String[] { "TLSv1", "SSLv3" }, null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", sslConnectionSocketFactory)
.build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
httpclient = HttpClients.custom()
.setDefaultCredentialsProvider(credsProvider)
.setDefaultCookieStore(cookieStore)
.setSSLSocketFactory(sslConnectionSocketFactory)
.setConnectionManager(cm)
.build();
RESULT: Didn't work. Got Error while trying to execute request. javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
回答1:
One of the above approaches should work in case of self-signed certificates, but the weird thing is you are getting same exception in all the approaches.
I feel during SSL session establishment or handshaking protocol is not being accepted either by client or by server.
The best solution here is to debug the application.
In case of tomcat, add -Djavax.net.debug=all in setenv.sh or setenv.bat files and then restart the server.
Or you can follow this tutorial.
The OP just needed to change the port when connecting to SSL:
//For HTTPS
HttpHost httpstarget = new HttpHost("mysite.com", 443, "https");
//For HTTP
HttpHost httptarget = new HttpHost("mysite.com", 80, "http");
回答2:
I'm using Apache HttpClient 4.5.3 and none of the above solutions helped. I always got the error
PKIX Path building failed
.
I found the solution in http://www.baeldung.com/httpclient-ssl
Here's my code:
try {
SSLContext sslContext = new SSLContextBuilder()
.loadTrustMaterial(null, (certificate, authType) -> true).build();
httpClient = HttpClients.custom().setSSLContext(sslContext)
.setSSLHostnameVerifier(new NoopHostnameVerifier())
.build();
} catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
e.printStackTrace();
}
回答3:
Very often you not only need to support self signed certificates, but also invoke multi-threaded requests, and so use a pooling connection manager. Here's how I do it:
private CloseableHttpClient newClient() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
SSLContext context = SSLContexts.custom()
.loadTrustMaterial(TrustSelfSignedStrategy.INSTANCE)
.build();
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory> create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", new SSLConnectionSocketFactory(context, NoopHostnameVerifier.INSTANCE))
.build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
return HttpClients.custom()
.setConnectionManager(connectionManager)
.build();
}
回答4:
public static HttpClient newClient() {
SSLContext sslcontext = null;
try {
sslcontext = SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
} catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
e.printStackTrace();
}
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslcontext,
(s, sslSession) -> true);
return HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory)
.build();
}
来源:https://stackoverflow.com/questions/39922714/ignore-self-signed-certificates-in-apache-httpclient-4-5