How to disable SSL certificat validation in Java
This fix will disable the SSL certificate validation. It is not recommanded in a production environment. A recommanded approach is to install the needed certificates on the JVM.
Create the following class:
import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; public class SSLFix public static void execute() TrustManager[] trustAllCerts = new TrustManager[] new X509TrustManager() public java.security.cert.X509Certificate[] getAcceptedIssuers() return null; > @Override public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException <> @Override public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException <> > >; SSLContext sc=null; try sc = SSLContext.getInstance("SSL"); > catch (NoSuchAlgorithmException e) e.printStackTrace(); > try sc.init(null, trustAllCerts, new java.security.SecureRandom()); > catch (KeyManagementException e) e.printStackTrace(); > HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); // Create all-trusting host name verifier HostnameVerifier validHosts = new HostnameVerifier() @Override public boolean verify(String arg0, SSLSession arg1) return true; > >; // All hosts will be valid HttpsURLConnection.setDefaultHostnameVerifier(validHosts); > >
Now whenever you want to create a SSL connection, add the following line just before the connection:
Bypass SSL Certificate Checking in Java
To disable or bypass SSL certificate checking is never a recommended solution for SSL issues, but at test environment – sometimes you may need this. In this tutorial, I am creating instances of org.apache.http.impl.client.DefaultHttpClient available till Apache HTTP Library version 4.2 and org.apache.http.impl.client.CloseableHttpClient available since Apache HTTP Library version 4.3.
DefaultHttpClient is a deprecated class now, so it’s suggested to use CloseableHttpClient class. Please remember to bypass the SSL checking only for debug purposes when we want to test a few secured APIs without setting up installing the certificate on the local machine.
1. Bypass SSL Certificate Checking using CloseableHttpClient
If you are working with the latest versions of the apache HTTP library, you should this version of the code.
public static CloseableHttpClient getCloseableHttpClient() < CloseableHttpClient httpClient = null; try < httpClient = HttpClients.custom().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() < public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException < return true; >>).build()).build(); > catch (KeyManagementException e) < LOGGER.error("KeyManagementException in creating http client instance", e); >catch (NoSuchAlgorithmException e) < LOGGER.error("NoSuchAlgorithmException in creating http client instance", e); >catch (KeyStoreException e) < LOGGER.error("KeyStoreException in creating http client instance", e); >return httpClient; >
To use CloseableHttpClient instance, use it in the below manner.
//Some custom method to craete HTTP post object HttpPost post = createPostRequest(); //Get http client CloseableHttpClient httpClient = getCloseableHttpClient(); //Execute HTTP method CloseableHttpResponse res = httpClient.execute(post); //Verify response if(res.getStatusLine().getStatusCode() == 200)
2. Bypass SSL Certificate Checking using DefaultHttpClient
If you are working on older versions of the apache HTTP library, you should this version of the code.
public static DefaultHttpClient getDefaultHttpClient() throws Exception < DefaultHttpClient httpClient = new DefaultHttpClient(); SSLContext ssl_ctx = SSLContext.getInstance("TLS"); TrustManager[] certs = new TrustManager[] < new X509TrustManager() < public X509Certificate[] getAcceptedIssuers() < return null; >public void checkClientTrusted(X509Certificate[] certs, String t) < >public void checkServerTrusted(X509Certificate[] certs, String t) < >> >; ssl_ctx.init(null, certs, new SecureRandom()); SSLSocketFactory ssf = new SSLSocketFactory(ssl_ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); ClientConnectionManager ccm = httpClient.getConnectionManager(); SchemeRegistry sr = ccm.getSchemeRegistry(); sr.register(new Scheme("https", 443, ssf)); return new DefaultHttpClient(ccm, httpClient.getParams()); >
To use DefaultHttpClient instance, use it in the below manner.
//Some custom method to craete HTTP post object HttpPost post = createPostRequest(); //Get http client DefaultHttpClient client = getDefaultHttpClient(); //Execute HTTP method HttpResponse httpResponse = client.execute(post); //Handle response
Once again, please do not use it on production environment because it defeats the whole purpose of having SSL security on first place.
3. Configure Spring RestTemplate
If we use this code in a Spring application, we can configure the RestTemplate bean in the following manner. Do not forget to comment out this code when moving to production.
@Configuration public class RestTemplateSSLBypassConfig < @Bean public RestTemplate restTemplate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException < TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) ->true; SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom() .loadTrustMaterial(null, acceptingTrustStrategy) .build(); SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext); CloseableHttpClient httpClient = HttpClients.custom() .setSSLSocketFactory(csf) .build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setHttpClient(httpClient); RestTemplate restTemplate = new RestTemplate(requestFactory); return restTemplate; > >
4. Configure Spring WebClient
We can also configure a WebClient that uses the insecure InsecureTrustManagerFactory as follows:
@Bean public WebClient createWebClient() throws SSLException < SslContext sslContext = SslContextBuilder .forClient() .trustManager(InsecureTrustManagerFactory.INSTANCE) .build(); HttpClient httpClient = HttpClient.create().secure(t ->t.sslContext(sslContext)); return WebClient.builder().clientConnector(new ReactorClientHttpConnector(httpClient)).build(); >
5. Possible Exception Message of SSLHandshakeException
If you have not set up the above code correctly, you may find the exception message below. This message confirms that SSL certificate matching is still failing.
javax.net.ssl.SSLHandshakeException: 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.ssl.Alerts.getSSLException(Alerts.java:192) at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1916) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:279) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:273) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1472) at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:213) at sun.security.ssl.Handshaker.processLoop(Handshaker.java:913) at sun.security.ssl.Handshaker.process_record(Handshaker.java:849) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1035) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1344) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1371) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1355) at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:394) at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:353) at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:141) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353) at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184) at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)
Drop me your questions in the comments section.
Disable Certificate Validation in Java SSL Connections
By design when we open an SSL connection in Java (e.g. through java.net.URL.openConnection(“https://….”)) the JSSE implementation of the SSL protocol performs few validations to ensure the requested host is not fake. This involves validation of the server’s X.509 certificate with the PKIX algorithm and checking the host name agains the certificate subject. If the SSL certificate is not validates as trusted or does not match the target host, an HTTPS and other SSL encrypted connection cannot be established and all attempts will result in SSLHandshakeException or IOException.
Example of HTTPS Connection in Java that will Fail Due to Certificate Validation Failure
Consider we are trying to download a resource from HTTPS server:
URL url = new URL("https://www.nakov.com:2083/"); URLConnection con = url.openConnection(); Reader reader = new InputStreamReader(con.getInputStream()); while (true) < int ch = reader.read(); if (ch==-1) < break; >System.out.print((char)ch); >
If the server uses self-signed X.509 certificate, we will get SSLHandshakeException the following exception during the SSL handshaking:
Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(Unknown Source) at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source) .
This exception can be avoided if we import the server’s self-signed certificate in the JVM trusted store, a file called “cacerts”. For more information see this post: http://www.java-samples.com/showtutorial.php?tutorialid=210.
We could have also another issue. If the server uses trusted certificate (issued from trusted CA like VeriSign), but for different host, we will get another exception (IOException) during the host verification step of the SSL handshaking:
Exception in thread "main" java.io.IOException: HTTPS hostname wrong: should be at sun.net.www.protocol.https.HttpsClient.checkURLSpoofing(Unknown Source) at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source) at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
How to Turn Off Certificate Validation in Java HTTPS Connections?
Avoiding these exceptions is possible by switching off the certificate validation and host verification for SSL for the current Java virtual machine. This can be done by replacing the default SSL trust manager and the default SSL hostname verifier:
import java.io.InputStreamReader; import java.io.Reader; import java.net.URL; import java.net.URLConnection; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.security.cert.X509Certificate; public class Example < public static void main(String[] args) throws Exception < // Create a trust manager that does not validate certificate chains TrustManager[] trustAllCerts = new TrustManager[] public void checkClientTrusted(X509Certificate[] certs, String authType) < >public void checkServerTrusted(X509Certificate[] certs, String authType) < >> >; // Install the all-trusting trust manager SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); // Create all-trusting host name verifier HostnameVerifier allHostsValid = new HostnameVerifier() < public boolean verify(String hostname, SSLSession session) < return true; >>; // Install the all-trusting host verifier HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid); URL url = new URL("https://www.nakov.com:2083/"); URLConnection con = url.openConnection(); Reader reader = new InputStreamReader(con.getInputStream()); while (true) < int ch = reader.read(); if (ch==-1) < break; >System.out.print((char)ch); > > >
Voilla! Now the code runs as expected: it downloads the resource from an https address with invalid certificate.
Be careful when using this hack! Skipping certificate validation is dangerous and should be done in testing environments only.