How to ignore SSL certificate errors in Apache HttpClient 4.4

HttpClient has long been popular for implementing outbound HTTP in Java. URL requests, HTTP remoting & service access are all common usecases.

For developers of HTTPS client applications, one scenario is common: wanting to test HTTPS connectivity, without needing a CA-signed certificate on each developer’s local appserver.

Developers can use a self-signed certificate on their server, but by default HttpClient (same as a web browser) will not accept untrusted connections. However, HttpClient’s SSL configuration can be modified to allow this.

Security aside, this technique is commonly done in earlier versions of HttpClient; but the configuration API (SSL configuration especially) API have changed radically in 4.4.

So, here’s how you can now accomplish this:

public HttpClient createHttpClient_AcceptsUntrustedCerts() {
	HttpClientBuilder b = HttpClientBuilder.create();

	// setup a Trust Strategy that allows all certificates.
	//
	SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
		public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
			return true;
		}
	}).build();
	b.setSslcontext( sslContext);

	// don't check Hostnames, either.
	// 		-- use SSLConnectionSocketFactory.getDefaultHostnameVerifier(), if you don't want to weaken
	HostnameVerifier hostnameVerifier = SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;

	// here's the special part:
	// 		-- need to create an SSL Socket Factory, to use our weakened "trust strategy";
	//		-- and create a Registry, to register it.
	//
	SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
	Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
			.register("http", PlainConnectionSocketFactory.getSocketFactory())
			.register("https", sslSocketFactory)
			.build();

	// now, we create connection-manager using our Registry.
	// 		-- allows multi-threaded use
	PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager( socketFactoryRegistry);
	b.setConnectionManager( connMgr);

	// finally, build the HttpClient;
	//		-- done!
	HttpClient client = b.build();
	return client;
}

This technique is essentially a workaround for individual developers & local appservers.. Proper test environments should always be set up properly with a CA-signed certificate.

So, when we make an SSL connection but allow any certificates — what are we actually doing here, and how does this affect security?

Trust checks are the means to verify identity & authenticity of the remote server. Bypassing these means the connection itself is still encrypted, but we can no longer verify who we’re talking to — it could be a “spoofed DNS” imposter, or a “man-in-the-middle” attack capturing/ and later replaying the conversation.

Of course, in a development environment these attacks should largely be theoretical — if we’re talking to 127.0.0.1 we’re pretty safe.

This code is extracted from an actual working 4.4 implementation. Other answers for earlier HttpClient versions are popular, but just don’t work.. To save others having to spend hours figuring it out, I posted this.

Enjoy!

See also:

20 thoughts on “How to ignore SSL certificate errors in Apache HttpClient 4.4”

  1. Hello, and thank you !

    You’re article helped me a lot !

    Would you know how to specify a port for the SSL connections, in this solution ?
    I was thinking Scheme would be good, but it’s deprecated in 4.4.
    I’m loosing hope ^^

    1. This code works fine. According the the HttpClient 4.4 source code, CloseableHttpClient implements HttpClient.

      Maybe you have some old JAR version still in your classpath.. ?

  2. This is deprecated in 4.4
    SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER

    A workaround is to implement HostnameVerifier.verify method to return ‘true’ always.

    1. Thanks for the tip Pankaj! HttpClient changes in 4.4 have been major.

      We’re glad at least this one piece of API is still backwards compatible 🙂

  3. The other option if you don’t need as much is to simply:

    setSSLHostnameVerifier(new NoopHostnameVerifier())

    when you’re building your client, i.e.:


    CloseableHttpClient client = HttpClients.custom().setSslcontext(sslContext)
    .setSSLHostnameVerifier(new NoopHostnameVerifier()).build();

  4. I’ve removed some more deprecation warnings coming with version 4.5. This is my (Scala) code:


    private val httpClient: CloseableHttpClient = {
    val trustStrategy = new TrustStrategy {
    override def isTrusted(x509Certificates: Array[X509Certificate], s: String) = true
    }
    val sslContext = new SSLContextBuilder().loadTrustMaterial(null, trustStrategy).build()
    val sslSocketFactory = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier)
    val socketFactoryRegistry =
    RegistryBuilder.create[ConnectionSocketFactory]()
    .register("http", PlainConnectionSocketFactory.getSocketFactory)
    .register("https", sslSocketFactory)
    .build()
    val connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry)
    HttpClients.custom()
    .disableRedirectHandling()
    .setSSLContext(sslContext)
    .setConnectionManager(connectionManager)
    .build()
    }

  5. I’m using 4.5, and nothing mentioned above worked for me. This, however, did:

    CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build();

    (similar to what Adam wrote above).

  6. The code above is working well on 4.5 except the deprecation of SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER

    just replace:
    HostnameVerifier hostnameVerifier = SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;

    with:

    HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;

    Adding .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) when build the httpClients doesn’t work for me.

  7. Well, I tried to reduce and delete deprecated tags:

    class SSLClient {

    static HttpClient getClient()
    throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {

    SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (arg0, arg1) -> true).build();
    return HttpClients.custom().setSSLContext(sslContext).setSSLHostnameVerifier(new NoopHostnameVerifier()).build();
    }
    }

    You can call to SSLClient.getClient().execute(…)
    HttpClient 4.5.8 used.

    Regards,

Leave a Reply to antonio Cancel reply

Your email address will not be published. Required fields are marked *