【问题标题】:Android Studio, javax.net.ssl.SSLHandshakeException: Unacceptable certificateAndroid Studio,javax.net.ssl.SSLHandshakeException:不可接受的证书
【发布时间】:2019-12-25 08:55:20
【问题描述】:

我正在尝试从 Android Studio 运行 Android Virtual Device。一切正常,直到我尝试从虚拟设备内部访问任何 Google 的服务。我们的网络正在使用公司代理,我们必须安装公司证书才能使应用程序正常工作。我通过keytool -importcert -trustcacerts ... 将证书安装到Java(jdk),然后以同样的方式将其安装到Android\Android Studio\jre\bin。然后使用adb push C:\certs\cert1.cer /sdcard/cert1.cer将证书上传到虚拟机中,并在Android的设置中应用。但我仍然收到错误

Caused by: javax.net.ssl.SSLHandshakeException: Unacceptable certificate: CN=CompanyName Root CA, OU=IT Department, O='CompanyName Professional' LLC, L=NY, ST=NY, C=EN

无论如何绕过是真的吗?如果我已经导入了证书,为什么它仍然要求提供证书。在浏览器中,如果在虚拟机中打开它,所有网站都可以正常工作。谢谢。

【问题讨论】:

  • 将其安装到模拟器中对于现代 Android 设备来说是错误的方式。您必须编辑应用程序的Network Security Configuration 以接受您的公司根 CA 证书。例如,请参阅this 问题。
  • 谢谢,但是如果我刚刚在虚拟android设备上打开Google Maps时出现错误怎么办?
  • 在这种情况下,你必须root模拟器,安装XPosed和模块“相信我”和“SSL Unpinning”(我上次使用这些模块时我必须使用最新的自我从他们的 Github 存储库编译的版本, XPosed 中的预编译模块太旧了. 请注意, 这完全禁用 SSL/TLS 安全检查. 从长远来看, 最好要求位于网络中的 PC 不通通过该代理(因为越来越多的应用程序使用与 SSL 代理概念完全不兼容的证书固定)。
  • 非常感谢。即使我在安全选项中添加了user defined 证书,您知道为什么会出现错误吗?并且仅适用于 Google 服务。
  • 添加 CA 证书作为用户定义的证书仅适用于较旧的 Android 版本(AFAIR Android 6 及更早版本)。此外,大多数 Google 应用都使用证书固定,因此它们永远不会接受您公司的根 CA 证书。

标签: java android android-studio ssl


【解决方案1】:

对于遇到此错误的任何人,我在 Android Xamarin 应用程序上收到此错误,它是由于设备的日期和时间不同步造成的。

【讨论】:

    【解决方案2】:

    将您的根 CA 证书作为“用户定义的证书”安装到模拟器中对于现代 Android 设备(Android 6+)来说是错误的方式。

    默认情况下,用户安装的 CA 证书不受应用信任。在有根设备上,您可以安装新的 CA 证书作为系统证书,如下所示:

    如果您的设备已获得 root 权限并安装了 Magisk,您还可以使用 Magisk Move Certificates 模块将用户安装的证书移动到系统存储中。

    自从 Google 推出 Android Network Security Configuration 以来,每个应用都必须明确地将用户定义的证书添加到信任列表中:

    res/xml/network_security_config.xml

    <?xml version="1.0" encoding="utf-8"?>
    <network-security-config>
        <base-config>
            <trust-anchors>
                <certificates src="system"/>
                <certificates src="user"/>
            </trust-anchors>
        </base-config>
    </network-security-config>
    

    每个未定义 Android 网络安全配置或具有此类配置但不包含 &lt;certificates src="user"/&gt; 条目的应用都会忽略您额外安装的证书。

    并确保AndroidManifest.xml&lt;application&gt; 标签中包含android:networkSecurityConfig 属性:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest ... >
        <application android:networkSecurityConfig="@xml/network_security_config"
                        ... >
            ...
        </application>
    </manifest>
    

    此外,一些应用程序(例如 Google 服务和 Play 商店)执行证书/密钥固定,这完全可以防止破坏 HTTPS 流量,除非系统被大量修改:

    完全禁用 SSL/TLS 证书检查

    您必须 root 设备并安装 EdXposed/Xposed + 多个模块才能允许 SSL/TLS 拦截,例如 TrustMeAlreadySSL Unpinning)。

    或者,您可以使用 Frida 和某些脚本来禁用 SSL/TLS 证书检查和一些固定实现。据我所知,基于 Frida 的 Objection 项目包含一些 SSL 取消固定脚本。

    警告:这样做会完全消除设备使用的每个 SSL/TLS/HTTPS 连接的安全性(直至使用的代理)。因此,不仅您,每个人都可以拦截设备建立的连接并以这种方式修改它们!

    【讨论】:

    【解决方案3】:

    最佳解决方案(工作):

    创建一个新类:HttpsTrustManager

    public class HttpsTrustManager implements X509TrustManager {
    
        private static TrustManager[] trustManagers;
        private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[]{};
    
        @Override
        public void checkClientTrusted(
                java.security.cert.X509Certificate[] x509Certificates, String s)
                throws java.security.cert.CertificateException {
    
        }
    
        @Override
        public void checkServerTrusted(
                java.security.cert.X509Certificate[] x509Certificates, String s)
                throws java.security.cert.CertificateException {
    
        }
    
        public boolean isClientTrusted(X509Certificate[] chain) {
            return true;
        }
    
        public boolean isServerTrusted(X509Certificate[] chain) {
            return true;
        }
    
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return _AcceptedIssuers;
        }
    
        public static void allowAllSSL() {
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
    
                @Override
                public boolean verify(String arg0, SSLSession arg1) {
                    return true;
                }
    
            });
    
            SSLContext context = null;
            if (trustManagers == null) {
                trustManagers = new TrustManager[]{new HttpsTrustManager()};
            }
    
            try {
                context = SSLContext.getInstance("TLS");
                context.init(null, trustManagers, new SecureRandom());
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (KeyManagementException e) {
                e.printStackTrace();
            }
    
            HttpsURLConnection.setDefaultSSLSocketFactory(context
                    .getSocketFactory());
        }
    }
    

    并在 HTTP 调用之前调用以下函数

    HttpsTrustManager.allowAllSSL();
    

    【讨论】:

    • 对于任何愿意使用它的人,请导入所有这些: import javax.net.ssl.HostnameVerifier;导入 javax.net.ssl.HttpsURLConnection;导入 javax.net.ssl.SSLContext;导入 javax.net.ssl.SSLSession;导入 javax.net.ssl.TrustManager;导入 javax.net.ssl.X509TrustManager;导入 java.security.KeyManagementException;导入 java.security.NoSuchAlgorithmException;导入 java.security.SecureRandom;导入 java.security.cert.X509Certificate;
    猜你喜欢
    • 2021-10-01
    • 2022-06-13
    • 2011-08-19
    • 2014-11-29
    • 1970-01-01
    • 2014-09-24
    • 2017-07-11
    • 1970-01-01
    • 2019-04-19
    相关资源
    最近更新 更多