Java: Overriding function to disable SSL certificate check

69,702

Solution 1

This should be sufficient. I use this when testing code against testing and staging servers where we don't have properly signed certificates. However, you should really really strongly consider getting a valid SSL certificate on your production server. Nobody wants to be wiretapped and have their privacy violated.

SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, new TrustManager[] { new TrustAllX509TrustManager() }, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier( new HostnameVerifier(){
    public boolean verify(String string,SSLSession ssls) {
        return true;
    }
});

And this.

import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;

/**
 * DO NOT USE IN PRODUCTION!!!!
 * 
 * This class will simply trust everything that comes along.
 * 
 * @author frank
 *
 */
public class TrustAllX509TrustManager implements X509TrustManager {
    public X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[0];
    }

    public void checkClientTrusted(java.security.cert.X509Certificate[] certs,
            String authType) {
    }

    public void checkServerTrusted(java.security.cert.X509Certificate[] certs,
            String authType) {
    }

}

Best of luck!

===UPDATE===

I just wanted to point out that there's a service called Let's Encrypt which automates the process of generating and setting up SSL/TLS certificates recognised by virtually everybody, and it's absolutely free!

Solution 2

Ignoring certs on a per-connection basis is much safer since any other code will still use the secure defaults.

The following code:

  • Overrides the trust manager and hostname verifier on a per-connection basis.
  • Reuses the SSLSocketFactory in order to support persistent connections, bypassing the expensive SSL handshake for repeated requests to the same server.

As others have stated, this should only be used for testing, and/or for internal systems communicating with other internal systems.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
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.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class TestPersistentConnection
{
    private static SSLSocketFactory sslSocketFactory = null;

    /**
     * Use the VM argument <code>-Djavax.net.debug=ssl</code> for SSL specific debugging;
     * the SSL handshake will appear a single time when connections are re-used, and multiple
     * times when they are not.
     * 
     * Use the VM <code>-Djavax.net.debug=all</code> for all network related debugging, but 
     * note that it is verbose.
     * 
     * @throws Exception
     */
    public static void main(String[] args) throws Exception
    {

        //URL url = new URL("https://google.com/");
        URL url = new URL("https://localhost:8443/");

        // Disable first
        request(url, false);

        // Enable; verifies our previous disable isn't still in effect.
        request(url, true);
    }

    public static void request(URL url, boolean enableCertCheck) throws Exception {
        BufferedReader reader = null;
        // Repeat several times to check persistence.
        System.out.println("Cert checking=["+(enableCertCheck?"enabled":"disabled")+"]");
        for (int i = 0; i < 5; ++i) {
            try {

                HttpURLConnection httpConnection = (HttpsURLConnection) url.openConnection();

                // Normally, instanceof would also be used to check the type.
                if( ! enableCertCheck ) {
                    setAcceptAllVerifier((HttpsURLConnection)httpConnection);
                }

                reader = new BufferedReader(new InputStreamReader(httpConnection.getInputStream()), 1);

                char[] buf = new char[1024];
                StringBuilder sb = new StringBuilder();
                int count = 0;
                while( -1 < (count = reader.read(buf)) ) {
                    sb.append(buf, 0, count);
                }
                System.out.println(sb.toString());

                reader.close();

            } catch (IOException ex) {
                System.out.println(ex);

                if( null != reader ) {
                    reader.close();
                }
            }
        }
    }

    /**
     * Overrides the SSL TrustManager and HostnameVerifier to allow
     * all certs and hostnames.
     * WARNING: This should only be used for testing, or in a "safe" (i.e. firewalled)
     * environment.
     * 
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     */
    protected static void setAcceptAllVerifier(HttpsURLConnection connection) throws NoSuchAlgorithmException, KeyManagementException {

        // Create the socket factory.
        // Reusing the same socket factory allows sockets to be
        // reused, supporting persistent connections.
        if( null == sslSocketFactory) {
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, ALL_TRUSTING_TRUST_MANAGER, new java.security.SecureRandom());
            sslSocketFactory = sc.getSocketFactory();
        }

        connection.setSSLSocketFactory(sslSocketFactory);

        // Since we may be using a cert with a different name, we need to ignore
        // the hostname as well.
        connection.setHostnameVerifier(ALL_TRUSTING_HOSTNAME_VERIFIER);
    }

    private static final TrustManager[] ALL_TRUSTING_TRUST_MANAGER = new TrustManager[] {
        new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
            public void checkClientTrusted(X509Certificate[] certs, String authType) {}
            public void checkServerTrusted(X509Certificate[] certs, String authType) {}
        }
    };

    private static final HostnameVerifier ALL_TRUSTING_HOSTNAME_VERIFIER  = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };

}

Many thanks to: http://runtime32.blogspot.com/2008/11/let-java-ssl-trust-all-certificates.html

Share:
69,702
Sumithlal
Author by

Sumithlal

Live to code

Updated on October 11, 2020

Comments

  • Sumithlal
    Sumithlal over 3 years

    The web service is rest over SSL and it has self signed certificate, hosted in remote system.I have already created a client accessing that web service. This is done by adding the certificate to the key store programatically.

    Now I heard that, it is not necessary to add certificate to key store for accesing a self signed web service. Instead we can disable the certificate check by overriding some methods. Is this true? Which are those methods? Please help.

  • Sumithlal
    Sumithlal over 10 years
    Thanks for your reply. This will work only when there is certificate added in jssecert or cacert. If the certificate is removed and run, the error i get SSLHandshakeException . Also it warns "Could not send Message."
  • Paaske
    Paaske over 10 years
    That should not be the case. When using a keystore with self-signed certificates, you set the keystore using javax.ssl.something=keystore.jks. This should not be set when using this method. I will retest it shortly.
  • user207421
    user207421 over 10 years
    The return value of getAcceptedIssuers() may not be null. See the Javadoc.
  • user207421
    user207421 over 10 years
    @Sumithlal You are mistaken. This implementation bypasses cacerts altogether.
  • maaartinus
    maaartinus over 9 years
    Are you perfectly sure that it works on per connection basis? With SSLContext.getInstance I never know if it's getter or what...
  • Josh Hansen
    Josh Hansen about 9 years
    Fairly sure. The only replacement that happens in the sample program is when enableCertCheck is false (via setAcceptAllVerifier(...)). If the system wide socket factory and hostname verifiers were replaced, then the second call to request(url, true) in main would print an exception on standard output. Otherwise the only way it would be changed is temporarily by connection itself, which would be restoring it after it was done with it, which seems unlikely.
  • David J. Liszewski
    David J. Liszewski over 8 years
    Does anyone else wonder how often this winds up as copy-pasta in production code?
  • Paaske
    Paaske over 8 years
    Shit.. Did I just lower Internet's security and privacy standards?
  • burduk
    burduk about 7 years
    For those, who tried to set up this method for web services, and failed- for me helped the following: WebService webSservice = service.getPort(WebService.class); HTTPConduit httpConduit = (HTTPConduit) ClientProxy.getClient(webSservice).getConduit(); httpConduit.setTlsClientParameters(getDefaultTSLParameters()‌​); and TLSClientParameters getDefaultTSLParameters() { TLSClientParameters parameters = new TLSClientParameters(); parameters.setUseHttpsURLConnectionDefaultHostnameVerifier(t‌​rue); parameters.setUseHttpsURLConnectionDefaultSslSocketFactory(t‌​rue); return parameters;}
  • jpp1jpp1
    jpp1jpp1 almost 7 years
    This works! I had the setDefaultSSLSocketFactory version for disabling cert check but it made my other connections to a second site that indeed needed cert checks fail. I just adapted this and now I can connect to both https sites
  • Nicholas DiPiazza
    Nicholas DiPiazza over 6 years
    Yep this is the one i needed too. needed to disable just the one HTTPS verification for a keep-alive https check. but i still needed it for the rest of the JVM. every other article or post seems to have statically turned off all ssl verification.