【问题标题】:Google Play Warning: How to fix incorrect implementation of HostnameVerifierGoogle Play 警告:如何修复 HostnameVerifier 的错误实现
【发布时间】:2017-05-17 13:46:56
【问题描述】:

今天我刚刚收到来自 Google 的这封电子邮件:

此电子邮件末尾列出的您的应用存在不安全 HostnameVerifier 接口的实现,它接受所有 与远程主机建立 HTTPS 连接时的主机名 setDefaultHostnameVerifier API,从而使您的应用易受攻击 到中间人攻击。攻击者可以读取传输的数据 (例如登录凭据),甚至更改上传输的数据 HTTPS 连接。

遗憾的是,我搜索了所有代码,发现没有使用 HostnameVerifier,也没有使用 setDefaultHostnameVerifier,甚至没有任何 HTTPS 连接!

我正在使用最新版本的 Google 兼容性库:25.0.1,在我的一些应用中使用 Google Ads 9.8.0。将 Ads 升级到 10.0.1,因为我只能假设罪魁祸首在那里?!

有人收到此警报吗?如果有,您是如何解决的?

【问题讨论】:

  • 你使用像 Glide 这样的第三方库吗?同样的警告在这里,不知道如何解决它。代码中没有 HostNameVerifier 的直接实现。
  • 仅使用 Google Ads 和 Google 兼容性库。我的一些项目包括 Xposed 框架 JAR、jcifs samba 源代码和 Apache commons.net 源代码。但受影响的项目没有这些。

标签: https warnings android-security


【解决方案1】:

此处相同 - 在 APK 中检测到不安全的主机名验证程序

您的应用正在使用不安全的 HostnameVerifier 实现。请 有关详细信息,请参阅此 Google 帮助中心文章,包括 修复漏洞的最后期限。我没有使用 HostnameVerifier 而不是调用 setDefaultHostnameVerifier。此外 - 我使用 OKHTTP 用于 http 请求的库。我希望定义 TrustManager 能解决 这个问题。

由于我没有继承HostnameVerifier 或调用setDefaultHostnameVerifier(),我认为它依赖于一些第3 方库。由于我无法检测到这样的库,我想我会尝试使用以下代码添加一个类

    HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
        public boolean verify(final String hostname, final SSLSession session) {
            if (check if SSL is really valid)
                return true;
            else
                return false;
        }
    });

到我的项目,看看它是否能解决问题。
所以我做到了,此外,我还添加了覆盖方法的每个 webView

@Override
            public void onReceivedSslError(WebView view, final SslErrorHandler handler, SslError error) {
// the main thing is to show dialog informing user
// that SSL cert is invalid and prompt him to continue without 
// protection: handler.proceed();
// or cancel: handler.cancel();
                String message;
                switch(error.getPrimaryError()) {
                    case SslError.SSL_DATE_INVALID:
                        message = ResHelper.getString(R.string.ssl_cert_error_date_invalid);
                        break;
                    case SslError.SSL_EXPIRED:
                        message = ResHelper.getString(R.string.ssl_cert_error_expired);
                        break;
                    case SslError.SSL_IDMISMATCH:
                        message = ResHelper.getString(R.string.ssl_cert_error_idmismatch);
                        break;
                    case SslError.SSL_INVALID:
                        message = ResHelper.getString(R.string.ssl_cert_error_invalid);
                        break;
                    case SslError.SSL_NOTYETVALID:
                        message = ResHelper.getString(R.string.ssl_cert_error_not_yet_valid);
                        break;
                    case SslError.SSL_UNTRUSTED:
                        message = ResHelper.getString(R.string.ssl_cert_error_untrusted);
                        break;
                    default:
                        message = ResHelper.getString(R.string.ssl_cert_error_cert_invalid);
                }
                mSSLConnectionDialog = new MaterialDialog.Builder(getParentActivity())
                        .title(R.string.ssl_cert_error_title)
                        .content(message)
                        .positiveText(R.string.continue_button)
                        .negativeText(R.string.cancel_button)
                        .titleColorRes(R.color.black)
                        .positiveColorRes(R.color.main_red)
                        .contentColorRes(R.color.comment_grey)
                        .backgroundColorRes(R.color.sides_menu_gray)
                        .onPositive(new MaterialDialog.SingleButtonCallback() {
                            @Override
                            public void onClick(MaterialDialog materialDialog, DialogAction dialogAction) {
                                mSSLConnectionDialog.dismiss();
                                handler.proceed();
                            }
                        })
                        .onNegative(new MaterialDialog.SingleButtonCallback() {
                            @Override
                            public void onClick(MaterialDialog materialDialog, DialogAction dialogAction) {
                                handler.cancel();
                            }
                        })
                        .build();
                mSSLConnectionDialog.show(); 
}

mWebView.setWebViewClient(new WebViewClient() {
... // other corresponding overridden methods
}

最后,谷歌说:

安全扫描完成
未检测到 APK 158 的已知漏洞。

但是我不确定是什么代码实现的,HostNameVerifieronReceivedSslError()mWebView.setWebViewClient

【讨论】:

  • 您是如何获得此安全扫描的?我刚刚发布了更新的 APK 并没有收到任何警告或看到此类扫描?可能我没注意。
  • 当您上传 apk (Menu->APK) 进行存储时,将其作为 Beta 版本进行存储(我不知道它是否与 Production 相同),然后过一段时间转到 Menu->发布前报告(APK 中的第三个选项)到“安全”选项卡。
  • """安全扫描完成未检测到 APK 26 的已知漏洞。""" 我收到此消息,但警报仍然存在。有什么想法吗?
  • 好的。问题解决了。更新问题状态大约需要 15 小时。 3 月 1 日是我的最后期限。
  • 任何人都可以在给定的答案中解释是否(检查 SSL 是否真的有效)
【解决方案2】:

根据从 Google 收到的邮件,此问题可能有两种可能性:

首先你必须检查你的包名没有使用谷歌限制的任何关键字。例如“com.companyname.android”,.android 是不允许的。其次是检查 HostNameVerifier

HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
    public boolean verify(final String hostname, final SSLSession session) {
        if (/* check if SSL is really valid */)
            return true;
        else
            return false;
    }
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-28
    • 1970-01-01
    相关资源
    最近更新 更多