【问题标题】:How to bypass SSL certificate validation in Android app?如何绕过 Android 应用程序中的 SSL 证书验证?
【发布时间】:2016-06-03 13:20:34
【问题描述】:

我的 Android 应用程序应该能够与任何启用 SSL 的服务器通信。由于我的应用程序是演示应用程序,并且我的客户在登录时在应用程序中添加了他们自己的 SSL 服务器详细信息,所以我不知道我需要验证哪个 SSL 证书。

以下是我之前的代码。

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();
    }

当我更新到 Playstore 时,它​​被拒绝了,原因如下

要正确处理 SSL 证书验证,请更改自定义 X509TrustManager 接口的 checkServerTrusted 方法中的代码,以在服务器提供的证书不符合您的期望时引发 CertificateException 或 IllegalArgumentException。对于技术问题,您可以发布到 Stack Overflow 并使用标签“android-security”和“TrustManager”。

我想更新类似这样的代码

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;
}

}

Playstore 接受这个吗?有没有更好的处理方法?

提前致谢。

【问题讨论】:

    标签: android ssl https google-play x509certificate


    【解决方案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);
            }
        }
    }
    

    使用这个技巧时要小心!跳过证书验证很危险,只能在测试环境中进行。

    【讨论】:

    • 是的,如果它工作,我会使用它发布应用程序接受答案,以便我帮助其他人
    • 当然。还有一个问题,您最近多久发布了该应用程序?因为我的初始代码在 6 个月前就被接受了。
    • 自上传应用两个月后
    • 感谢@MuhammadYounas,这有帮助。我们能在 swift ios 中得到类似的东西吗?
    【解决方案2】:

    引用以下解决方案: https://gist.github.com/aembleton/889392

    以下代码禁用对任何新的 HttpsUrlConnection 实例的 SSL 证书检查:

     /**
     * 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();
        }
    }
    

    【讨论】:

    • 我需要从哪里调用这个方法?
    • 这并不重要 - 在您的代码中的任何位置 - 只需在每个应用程序生命周期调用一次
    【解决方案3】:

    如果有人希望在 NativeScript Android 应用程序中禁用 SSL 证书检查,以下是将Elad's answer's 代码转换为 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.HttpsURLConnection.setDefaultHostnameVerifier(
            new javax.net.ssl.HostnameVerifier({
              verify: function (hostname, session) {
                return true
              }
            })
          )
        } catch (e) {
          console.log('e :>> ', e);
        }
      }
    
      disableSSLCertificateCheckin()
    

    谢谢@Elad

    【讨论】:

      猜你喜欢
      • 2021-02-08
      • 2010-11-09
      • 2014-07-07
      • 2017-08-29
      • 1970-01-01
      • 2021-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多