Ignore self-signed certificates in Apache HTTPClient 4.5
Solution 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");
Solution 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();
}
Solution 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();
}
Solution 4
This problem is about SSL connection. When you try to connect to some resource https protocol requires to create secured connection. That means only your browser and website server know what data is being sent in requests bodies. This security is achieved by ssl certificates that stored on website and are being downloaded by your browser (or any other client, Apache Http Client in our case) with first connection to host. There are RSA256 encryption and many other cool things around. But in the end of a day: In case certificate is not registered or is invalid you will see certificate error (HTTPS connection is not secure). To fix certificate error website provider need to buy it for particular website or fix somehow e.g. https://www.register.com/ssl-certificates
however there is an bypass when you skip ssl verification with
(s, sslSession) -> true
that is security violation because you are not 100% sure that your data is secured, however this solution can used for testing or configuration when use test data and trusted websites
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();
}
Katie
Software Engineer specializing in everything web. These are a few of my favorite things: angular node.js javascript go python java c++ bash jquery katies.io
Updated on June 05, 2022Comments
-
Katie almost 2 years
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 withTrustSelfSignedStrategy
.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
-
Katie over 7 yearsYeah, you're right. I just tried to go to the actual site and I think it's down lol they might have been working this whole time
-
M-- about 7 yearsAdd some comments and description.