30

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.

Community
  • 1
  • 1
Sumithlal
  • 373
  • 1
  • 4
  • 14
  • 3
    A Web service should not have a self-signed certificate. Period. Pay the money and get it signed by a CA. What you have heard is indeed correct but it is also highly undesirable. It requires special programming at the client, which introduces (a) security issues, (b) development risks, and (c) deployment problems. – user207421 Nov 01 '13 at 08:56
  • 4
    The web service is not published yet. It is under work. That is why now it is not certified by a trusted CA. It is known that using service by disabling those certificate check is undesirable. Eventhough I need to check it. Please help. Thanks @EJP – Sumithlal Nov 01 '13 at 09:05
  • 3
    Any effort expended towards a temporary solution (a) is wasted time and money and (b) introduces a security risk, i.e. that you will 'accidentally' deploy it in production. Spend the money now. It's only a couple of hundred bucks. – user207421 Nov 01 '13 at 09:08
  • @EJP, All the issues are there. But for a study purpose, Now I need to access that services by disabling this check. – Sumithlal Nov 01 '13 at 09:17
  • 2
    @Sumithlal, for study purpose, if you really can't purchase a certificate, it would be better to use your own CA (tools like xca or tinyca can help) and deploy your own CA cert in your client's truststore (not necessarily programmatically). That's certainly more realistic and less prone to security bugs than changing how the certs are verified in the code. – Bruno Nov 01 '13 at 11:12

3 Answers3

39

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!

Paaske
  • 4,345
  • 1
  • 21
  • 33
  • 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." – Sumithlal Nov 01 '13 at 09:52
  • 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. – Paaske Nov 01 '13 at 10:05
  • 2
    The return value of getAcceptedIssuers() may not be null. See the Javadoc. – user207421 Nov 01 '13 at 21:40
  • @Sumithlal You are mistaken. This implementation bypasses cacerts altogether. – user207421 Nov 01 '13 at 21:42
  • 1
    Does anyone else wonder how often this winds up as copy-pasta in production code? – David J. Liszewski Nov 01 '15 at 01:49
  • 2
    Shit.. Did I just lower Internet's security and privacy standards? – Paaske Nov 01 '15 at 07:09
  • 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(true); parameters.setUseHttpsURLConnectionDefaultSslSocketFactory(true); return parameters;}` – burduk Apr 23 '17 at 07:06
13

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

Josh Hansen
  • 141
  • 1
  • 3
  • 2
    Are you perfectly sure that it works on per connection basis? With `SSLContext.getInstance` I never know if it's getter or what... – maaartinus Oct 02 '14 at 01:05
  • 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. – Josh Hansen Feb 25 '15 at 23:25
  • 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 – jpp1jpp1 Jul 05 '17 at 18:09
  • 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. – Nicholas DiPiazza Aug 30 '17 at 17:37
0
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) {
                    }
                }
            };
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

            HostnameVerifier allHostsValid = new HostnameVerifier() {
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            };
            HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
            GetCustomerPhone http = new GetCustomerPhone(); 

    System.out.println("Processing..");     
     try{
            http.sendPost();    
        }
    catch(Exception e){
            e.printStackTrace();
        }               
}

I think it will working fine.because it fine of me...

Dusmant
  • 1
  • 2