32

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.

5
  • 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. Commented Nov 1, 2013 at 8: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 Commented Nov 1, 2013 at 9: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. Commented Nov 1, 2013 at 9:08
  • @EJP, All the issues are there. But for a study purpose, Now I need to access that services by disabling this check. Commented Nov 1, 2013 at 9: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. Commented Nov 1, 2013 at 11:12

3 Answers 3

41

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!

Sign up to request clarification or add additional context in comments.

7 Comments

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."
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.
The return value of getAcceptedIssuers() may not be null. See the Javadoc.
Does anyone else wonder how often this winds up as copy-pasta in production code?
Shit.. Did I just lower Internet's security and privacy standards?
|
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

4 Comments

Are you perfectly sure that it works on per connection basis? With SSLContext.getInstance I never know if it's getter or what...
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.
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
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.
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...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.