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.
You can try to bypass a security measure like SSL pinning only when the security measure is in place. If you are starting an Android app pentest, the initial step is to understand if the app has SSL pinning.
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.
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();
}
}
In case someone is looking to disable SSL certificate checking in a NativeScript Android app, here's how to convert Elad's answer's code to JavaScript:
const disableSSLCertificateCheckin = function () {
const trustAllCerts = [new javax.net.ssl.X509TrustManager({
getAcceptedIssuers: function () {
return null
},
checkClientTrusted: function (arg0, arg1) {
// Not implemented
},
checkServerTrusted: function (arg0, arg1) {
// Not implemented
},
})]
try {
const sc = javax.net.ssl.SSLContext.getInstance('TLS')
sc.init(null, trustAllCerts, new java.security.SecureRandom())
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory())
javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
new javax.net.ssl.HostnameVerifier({
verify: function (hostname, session) {
return true
}
})
)
} catch (e) {
console.log('e :>> ', e);
}
}
disableSSLCertificateCheckin()
Thanks @Elad!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With