Ignore self-signed certificates in Apache HTTPClient 4.5

19,573

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();
        }
Share:
19,573
Katie
Author by

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, 2022

Comments

  • Katie
    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:

    Related StackOverflow Questions - Here's some links of the solutions I've tried:

    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

  • Katie
    Katie over 7 years
    Yeah, 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--
    M-- about 7 years
    Add some comments and description.