Menu

Nakov.com logo

Thoughts on Software Engineering

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" <strong>java.io.IOException: HTTPS hostname wrong: should be <www.nakov.com></strong>
	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[] {new X509TrustManager() {
				public java.security.cert.X509Certificate[] getAcceptedIssuers() {
					return null;
				}
				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.

Comments (91)

91 Responses to “Disable Certificate Validation in Java SSL Connections”

  1. Amer says:

    Can this code be used in j2me?

    Thanks

  2. nakov says:

    I don’t know. You could test it in Java ME environment, of course.

  3. kaz says:

    Is this supposed to work when running the client from the command line? I have implemented this but I am still receiving the same error. You have any idea what may be happening?

  4. nakov says:

    I have no idea. It worked at the time it was written. Now we have newer Java versions that could possibly work differently.

  5. kaz says:

    It works … I found the issue I was having … it was in an old script that was being used to run the client. 😉 it was setting the command line parameter: -Djava.protocol.handler.pkgs=com.sun.net.ssl.internal.www.protocol … which apparently did not recognize my hostname verifier. Thx for the response.

    JFYI … all that is needed when using JAX-WS is:

    HttpsURLConnection.setDefaultHostnameVerifier( new HostnameVerifier() {
    public boolean verify(String urlHostName, SSLSession session) {
    log.debug( “Warning: URL Host: ” + urlHostName + ” vs. ” + session.getPeerHost() );
    return true;
    }
    } );

  6. […] to a HTTPS server from Java and ignore the validity of the security certificate as well as Disable Certificate Validation in Java SSL Connections, but the accepted answer to the first is for HttpClient 4.0 (unfortunately I cannot upgrade, unless […]

  7. Madhu says:

    This is very helpful, it worked perfectly. The one change I did was making these two calls on the connection instance (instead of static calls)

    httpsConnection.setSSLSocketFactory(sc.getSocketFactory());
    httpsConnection.setHostnameVerifier(allHostsValid);

  8. […] I actually disabled the HTTPS certificate check by using the method described in this nifty blog: http://www.nakov.com/blog/2009/07/16/disable-certificate-validation-in-java-ssl-connections/. In actual production use, however, HTTPS URLs are handled by using the actual certificates […]

  9. Sweet – just what I needed – thank you. Only thing I needed to add was a permission in my java.policy file like so:
    permission javax.net.ssl.SSLPermission “setHostnameVerifier”;

  10. Federico says:

    Thank you very much!!!! very usefull!

  11. Prafulla says:

    it works, thanks much

  12. Prafulla says:

    it works, great help!!

  13. Daniel says:

    Very great, thank you!

  14. jeff says:

    Thanks. Very helpful — I was using a similar but incomplete solution that worked in some cases but not all. Not sure why it sometimes worked but anyhow, this is great!

  15. Pharmd57 says:

    Hello! fddgegf interesting fddgegf site! I’m really like it! Very, very fddgegf good!

  16. Shashank says:

    Thanks…
    Very Helpful

  17. me says:

    Can anybody help me why am I getting the following error ?
    Exception in thread “main” java.io.IOException: Server returned HTTP response code: 401 for URL: https://www.nakov.com:2083/
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1615)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
    at MainProject.Cert.main(Cert.java:58)

    • nakov says:

      This URL requires authentication (username + password). It says “401 Access Denied” and this is its correct behavior. HTTP code 401 is returned when the server needs authentication. You could try accessing another URL, e.g. https://appharbor.com/.

  18. me says:

    @nakov: the example you provided: https://appharbor.com/. has a valid certificate. So, Java can deal with it without the need to use the code. Can you provide me with another example for expired or self-signed certificate if you have any ?

  19. Raj says:

    Excellent post. Vey nice!!

  20. Russell Grokett says:

    Just a note if you use HTTPS Mutual SSL Authentication, this can cause a “sslv3 alert bad certificate” error.
    javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    as it nulls the SSL certs needed for the two-way handshake.
    Its fine to use this code if you do not use Mutual SSL Auth.

  21. Abhishek says:

    how do I pass username and password to the htpps connection.
    I am trying this but its not working

    byte[] encodedPassword = ( userName + “:” + password ).getBytes();
    BASE64Encoder encoder = new BASE64Encoder();
    con.setRequestProperty( “Authorization”,
    “Basic ” + encoder.encode( encodedPassword ) );

  22. Anonymous says:

    Thanks, it worked!

  23. Peter Altankov says:

    Thanks Svetlin, works like a charm!

  24. vutty says:

    Thanks. it is working.

  25. Steve says:

    How does one programmatically undo this change and get back to the original SSL security settings?

  26. Stefan says:

    Thank you very much Nakov. It´s very useful information!

  27. Ashis says:

    Thanks a lot. solved my issue

  28. Ehis says:

    Thanks a lot. It helped.

  29. getting error

    java.lang.UnsupportedClassVersionError: Bad version number in .class file

  30. Emilse says:

    Great!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    Thanks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  31. Miguel says:

    thanks very much!! Your code was very useful for me!!

  32. Anonymous says:

    thank you

  33. Bernardo says:

    You saved my life!!!! I have been trying to work my way around this problems for days…
    It works like a charm for me…
    If you ever come down to Mexico, we will have a beer (or two)

  34. Wasenshi says:

    You saved my life too!!
    If you ever come to Thailand in Asia we will have a beer(or two)

  35. Umair says:

    It worked for me.
    Thank You Very Much!!!

  36. Magesh says:

    Simply super…I got it:)

  37. Shashika says:

    This is very useful. Thank you!

  38. Alex Zaharow says:

    Big thanks! You bring the light for many years!

  39. Sunset Dreamer says:

    great article and tutorial through the steps

  40. wnieva says:

    Plz… I can’t resolved my problem.
    This’s my error:

    [20/09/2016 11:31:06,407] INFO [web.servlet.CheckUpdate:65] [doGet] [] ERROR: Obteniendo versión de APP. FATAL Alert:BAD_CERTIFICATE – A corrupt or unuseable certificate was received.

  41. Thank you, worked flawlessly.

  42. simon.kim says:

    wow~ thanks.

  43. jwitt98 says:

    Awesome job putting this all together and sharing.. thanks!

  44. Thanks, it works and it save my tests 🙂

  45. Amit says:

    Awesome article! Saved me lot of work

  46. Mzee says:

    Thanks! This article saved me so much trouble.

  47. […] I fixed the problem by disabling HTTPS checks using the approach presented here: […]

  48. Yashwanth says:

    Its Works thanks

  49. Andreea says:

    Thank you! Was truly helpful!

  50. aAshish verma says:

    thank you very much.

  51. Stefan Cordes says:

    Great post!

    Thank you very much for getting rid of

    “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)”

    in test environments !!!
    (without adding them to the JVM cacerts file)

    • Leo stany says:

      Hi Stefan, This code disables the SSL in HTTPS connection perfectly. Can you explain me how disabling SSL in Https connection is different from having a simple http connection?

  52. gianluca de pascale says:

    does it works for mail connections too?
    i’m trying to use this approach with an smpts connection,
    but so far no luck. :-\

  53. E.J. says:

    Great post! It works like a charm!

  54. gvshan says:

    Is it possible to disable cert validation or basically avoid the – “PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target” error when trying a POST through unirest?

    For example, I use HttpResponse response = Unirest.post(“https://nakov.com/blog/2009/07/16/disable-certificate-validation-in-java-ssl-connections/”) to get a response from the website, but getting cert error.
    I can add the server cert to cacerts to resolve the issue but i wanted to disable the certificate check and test the connection.

  55. Thanks it worked for me. 🙂

  56. Pranay says:

    I am getting Server returned HTTP response code: 401

  57. Saeed says:

    Thanks, it worked like charm

  58. […] un serveur HTTPS à partir de Java, et d'ignorer la validité du certificat de sécurité ainsi que Désactiver la Validation de Certificat en Java les Connexions SSL, mais le a accepté de répondre à la première est pour HttpClient 4.0 (malheureusement je ne […]

  59. […] After days of research, installing java packages to help boost my level of encryption, trying to import the DCU cacert as a trusted key and trying to override the exception handler i’ve finally found a script that gets around the SSL certificate by installing an all trusting trust manager. This code isn’t mine and i’m not claiming it to be but after days spent trying to get around it by myself I think this is my best option going forward. The code is taken from “https://nakov.com/blog/2009/07/16/disable-certificate-validation-in-java-ssl-connections&#8221; […]

  60. Thanks a lot! It worked for us

  61. Deva says:

    Thanks Nakov!!!. The code was worked as expected.

  62. Adolfo says:

    it works, thanks

  63. Leo Stany says:

    Hi Nakov,

    This code disables the SSL perfectly.
    Can you explain me What is the difference between http connection and disabling SSL in Https connection?

  64. […] 我通过使用此处介绍的方法禁用HTTPS检查来解决此问题: […]

  65. Praveena says:

    Hello Nakov,

    @nakov, We have implemented this solution in our application to disable SSL warning.

    Do you have any idea about this exception in the code ? Could you please suggest ?

    java.io.IOException: Server returned HTTP response code: 400 for URL

    Thanks.

  66. HYPHENX says:

    Thank you very much !

  67. […] I fixed the problem by disabling HTTPS checks using the approach presented here: […]

  68. […] I fixed the problem by disabling HTTPS checks using the approach presented here: […]

  69. Sudi says:

    Thanks for this, it has worked for me.

  70. bobby says:

    Thanks for the code, very helpful for test environment

  71. Paresh says:

    I am still not able to resolve, keep getting below exception. What I could be missing?

    Exception in thread “main” javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake
    at java.base/sun.security.ssl.SSLSocketImpl.handleEOF(SSLSocketImpl.java:1321)

  72. Paresh says:

    I am still not able to resolve, keep getting below exception. What I could be missing?

    Kindly suggest. Thanks!

    Exception in thread “main” javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake
    at java.base/sun.security.ssl.SSLSocketImpl.handleEOF(SSLSocketImpl.java:1321)

  73. Coach Training

    Svetlin Nakov – Svetlin Nakov – Official Web Site and Blog » Disable Certificate Validation in Java SSL Connections

RSS feed for comments on this post. TrackBack URL

Leave a Reply to Amit