How to bypass SSL certificate validation in Android app?

24,678

Solution 1

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"); // Add in try catch block if you get error.
        sc.init(null, trustAllCerts, new java.security.SecureRandom()); // Add in try catch block if you get error.
        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_url_here");
        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);
        }
    }
}

Be careful when using this hack! Skipping certificate validation is dangerous and should be done in testing environments only.

Solution 2

quoting the solution from: https://gist.github.com/aembleton/889392

The following code disables SSL certificate checking for any new instances of HttpsUrlConnection:

 /**
 * Disables the SSL certificate checking for new instances of {@link HttpsURLConnection} This has been created to
 * aid testing on a local box, not for use on production.
 */
public static void disableSSLCertificateChecking() {
    TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        @Override
        public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
            // Not implemented
        }

        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
            // Not implemented
        }
    } };

    try {
        SSLContext sc = SSLContext.getInstance("TLS");

        sc.init(null, trustAllCerts, new java.security.SecureRandom());

        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } });
    } catch (KeyManagementException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
}
Share:
24,678
Ganesh K
Author by

Ganesh K

Updated on July 12, 2022

Comments

  • Ganesh K
    Ganesh K almost 2 years

    My Android application should be able to communicate to any SSL enabled servers. As my app is demo application and my customers add their own SSL server details in the app while logging in, so upfront I don't know which SSL certificate I need to validate.

    Following is my earlier code.

    public SSLSocketFactory getSSLSocketFactory(String hostname) {
            try {
                HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                });
                SSLContext context = SSLContext.getInstance("TLS");
                context.init(null, new X509TrustManager[] { new X509TrustManager() {
                    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    }
    
                    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    }
    
                    public X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[0];
                    }
                } }, new SecureRandom());
                HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
            } catch (Exception e) {
                e.printStackTrace();
            }
            return  HttpsURLConnection.getDefaultSSLSocketFactory();
        }
    

    When I updated my to playstore, it was rejected with below reason

    To properly handle SSL certificate validation, change your code in the checkServerTrusted method of your custom X509TrustManager interface to raise either CertificateException or IllegalArgumentException whenever the certificate presented by the server does not meet your expectations. For technical questions, you can post to Stack Overflow and use the tags “android-security” and “TrustManager."

    I would like to update my code similar to this

    public static HttpClient wrapClient(HttpClient base) {
    try {
        SSLContext ctx = SSLContext.getInstance("TLS");
        X509TrustManager tm = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { }
    
            public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { }
    
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        ctx.init(null, new TrustManager[]{tm}, null);
        SSLSocketFactory ssf = new SSLSocketFactory(ctx);
        ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        ClientConnectionManager ccm = base.getConnectionManager();
        SchemeRegistry sr = ccm.getSchemeRegistry();
        sr.register(new Scheme("https", ssf, 443));
        return new DefaultHttpClient(ccm, base.getParams());
    } catch (Exception ex) {
        return null;
    }
    

    }

    Does playstore accept this? is there any better way to handle this?

    Thanks in Advance.

  • Muhammad Younas
    Muhammad Younas about 8 years
    yes i publish app using it if it work accept answer so that i help other
  • Ganesh K
    Ganesh K about 8 years
    Sure. One more question how recent you published the app? because my initial code was accepted 6months back.
  • Muhammad Younas
    Muhammad Younas about 8 years
    two months since i upload the app
  • Sajid Zeb
    Sajid Zeb over 4 years
    Thanks @MuhammadYounas this helps. Can we get something similar in swift ios?
  • Shailesh
    Shailesh over 3 years
    from where I need to call this method?
  • Elad
    Elad over 3 years
    it doesn't really matter - anywhere in your code - just call it once per application lifetime
  • Panache
    Panache about 2 years
    It works good, but if i have http connection in various java classes, do i need to add this everywhere?
  • Muhammad Younas
    Muhammad Younas almost 2 years
    @Panache why you are keeping the HTTP connection in various java classes the good practice is to keep in a single class and inject that class where it is required using any DI library