【问题标题】:How to fix unsafe implementation of X509TrustManager in Android app如何修复 Android 应用中 X509TrustManager 的不安全实现
【发布时间】:2016-02-20 23:53:54
【问题描述】:

Google 已告知我在我的 Android 应用程序中有一个不安全的接口 X509TrustManager 实现,需要按如下方式更改我的代码:

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

如何修改以下代码来解决上述问题?

public EasySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
    super(truststore);

    TrustManager tm = new X509TrustManager()  {
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    };

    mContext.init(null, new TrustManager[] { tm }, null);
}

【问题讨论】:

  • 我也遇到这个问题,请问有解决办法吗?
  • "如何修改以下代码来解决上述问题?" -- 你删除它。

标签: android-security trustmanager


【解决方案1】:

我已经使用以下代码解决了这个问题:

public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                try {
                    chain[0].checkValidity();
                } catch (Exception e) {
                    throw new CertificateException("Certificate not valid or trusted.");
                }
            }

【讨论】:

  • @Glowcall,我应该在哪里写上面的代码来解决错误?我的意思是在哪个活动下?
  • @anddev 受影响的活动/类别取决于 Google 在您收到的有关此警告的电子邮件中提到的内容。只需在您的源代码中找到相关的 checkServerTrusted 方法并将其替换为上述方法即可;那应该可以解决它。
  • 如果 CA 是自签名 CA,则此解决方案不是一个好主意!有时我们必须接受自签名 CA
  • 请注意:当应用程序处于 Beta 或 Alpha 阶段时,Google 不会检查接口 X509TrustManager 的实现。仅在发布后仅生产五个小时。
  • 不要使用这个非常糟糕的代码!该代码允许中间人攻击并使 SSL 的整个点为空。 checkValidity() 方法仅检查证书是否未过期而没有其他内容,这意味着此代码将愉快地接受任何未过期的证书,即使证书是用于另一台服务器且未由任何人签名。
【解决方案2】:

如果您在使用的外部库中遇到此问题,请检查 appache libraray 是否是导致此问题的原因。

对我来说,apache 库导致了错误:我使用了已弃用的类 - MultipartEntity。这个类使用SSLContextBuilder 它使用TrustManagerDelegate。 TrustManagerDelegate 实现 X509TrustManager,在将应用程序上传到 google play 商店时会导致“不安全的 TrustManager 实现”错误。

解决方案是:使用 MultipartEntityBuilder 代替已弃用的 MultipartEntity 类。

例如:

MultipartEntity httpMultipart = new MultipartEntity();
String contentType = httpMultipart.getContentType().getValue();

将被替换为:

MultipartEntityBuilder httpMultipart = new MultipartEntityBuilder();
String contentType = httpMultipart.build().getContentType().getValue();

【讨论】:

  • 是的,你是对的,我也面临同样的问题
【解决方案3】:

我遇到过这个问题。如果你的代码是这样的:

 TrustManager tm = new X509TrustManager()  {
    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    }

    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    }

    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }
};

它将接受所有证书,这是一个坏主意,所以谷歌给你发邮件。 我们也可以进行更改以接受自签名证书。 我解决了,here is my question and my solution

【讨论】:

  • 谢谢,但请参阅我的答案以获得更简单的修复。来自 Google 的警告已从 Play 开发者控制台中消失。
  • 查看我放链接的解决方案
【解决方案4】:

添加升级版的 OKttps 为我在 Android 10 中崩溃

implementation 'com.squareup.okhttp3:okhttp:4.8.0'

【讨论】:

    【解决方案5】:

    如果您使用的是HttpClient,那么@Nabeel 的解决方案非常好,但如果您使用的是HttpsUrlConnection,那么这段代码非常适合:

    import android.util.Log;
    
    import java.security.SecureRandom;
    import java.security.cert.CertificateException;
    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.TrustManager;
    import javax.net.ssl.X509TrustManager;
    
    /**
     * TrustManager that accepts all certificates and hosts.
     * Useful when you want to use HTTPS but you have self-signed certificates.
     * Works with HttpsUrlConnection.
     * Use at your own risk and only for development.
     *
     * @author gotev (Aleksandar Gotev)
     */
    public class AllCertificatesAndHostsTruster implements TrustManager, X509TrustManager {
    
        @Override
        public final void checkClientTrusted(final X509Certificate[] xcs, final String string)
                throws CertificateException {
        }
    
        @Override
        public final void checkServerTrusted(final X509Certificate[] xcs, final String string)
                throws CertificateException {
        }
    
        @Override
        public final X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    
        /**
         * Gets an {@link SSLContext} which trusts all certificates.
         * @return {@link SSLContext}
         */
        public static SSLContext getSSLContext() {
            final TrustManager[] trustAllCerts =
                    new TrustManager[] {new AllCertificatesAndHostsTruster()};
    
            try {
                final SSLContext context = SSLContext.getInstance("SSL");
                context.init(null, trustAllCerts, new SecureRandom());
                return context;
    
            } catch (Exception exc) {
                Log.e("CertHostTruster", "Unable to initialize the Trust Manager to trust all the "
                        + "SSL certificates and HTTPS hosts.", exc);
                return null;
            }
        }
    
        /**
         * Creates an hostname verifier which accepts all hosts.
         * @return {@link HostnameVerifier}
         */
        public static HostnameVerifier getAllHostnamesVerifier() {
            return new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            };
        }
    
        /**
         * Call this method once before all your network calls
         * to accept all the self-signed certificates in HTTPS connections.
         */
        public static void apply() {
            final TrustManager[] trustAllCerts =
                    new TrustManager[] {new AllCertificatesAndHostsTruster()};
    
            try {
                final SSLContext context = SSLContext.getInstance("SSL");
                context.init(null, trustAllCerts, new SecureRandom());
                HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
                HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
    
                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                });
    
            } catch (Exception exc) {
                Log.e("CertHostTruster", "Unable to initialize the Trust Manager to trust all the "
                        + "SSL certificates and HTTPS hosts.", exc);
            }
        }
    }
    

    来源:https://gist.github.com/gotev/6784c1303793c6ee9e56

    然后要使用自签名证书,只需调用:

    AllCertificatesAndHostsTruster.apply();
    

    在任何网络调用之前。

    【讨论】:

    • 这很糟糕,不应该用于任何事情,如果您有自签名证书,请检查该证书,接受任何内容都会使 SSL 毫无意义。
    • 是的,答案很好,你节省了我的时间
    • 有谁知道这个异常在哪里被捕获?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-23
    相关资源
    最近更新 更多