如何在将应用上传到Google Play控制台

时间:2017-10-08 10:29:47

标签: android-security

我更新了应用的版本代码和版本名称,但我收到了来自Google Play的警告消息

  

您的应用正在使用HostnameVerifier接口的不安全实现。您可以在此Google帮助中心文章中找到有关如何解决问题的详细信息。

提前致谢

2 个答案:

答案 0 :(得分:2)

有很多我们认为在这个 Flutter 项目 中是正确的版本,但一次又一次地被拒绝,但最终,我们想通了。

Pubspec.yaml - 以前的版本。

flutter_html: ^0.11.1
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  http: ^0.12.0+2
  provider: ^4.1.3
  logger: ^0.7.0+2
  shared_preferences: ^0.5.4+6
  json_annotation: ^3.0.0
  flutter_dotenv: ^2.1.0
  flutter_swiper: ^1.1.6
  package_info: ^0.4.0+3
  get_version: ^0.2.0+1
  uuid: ^2.0.4
  flappy_translator: ^1.2.2
  flutter_circular_chart: ^0.1.0
  percent_indicator: "^2.1.1"
  intl: ^0.16.0
  bezier_chart: ^1.0.15
  charts_flutter: ^0.8.1
  fl_chart: ^0.6.0
  flutter_native_timezone: ^1.0.4
  url_launcher: ^5.7.8
  permission_handler: ^5.0.1+1
  onesignal_flutter: 2.6.1
  flutter_braintree: 1.1.0
  after_layout: ^1.0.7+2
  flutter_svg: ^0.19.0
  custom_switch_button: 0.5.0
  wc_flutter_share: ^0.2.2
  esys_flutter_share: ^1.0.2
  just_audio: ^0.4.4
  cached_network_image: 2.2.0+1
  sqflite: ^1.3.1
  cupertino_icons: ^0.1.2
  in_app_purchase: 0.3.4+5

主机名验证

    HttpsURLConnection.setDefaultHostnameVerifier { hostname, arg1 ->      
val herokuPattern = “PROJECTNAME-(dev|stg|prd)\\.herokuapp.com”.toRegex()      
val awsPattern = “PROJECTNAME-(dev|stg|prd)\\.s3\\..*\\.amazonaws.com”.toRegex()
              herokuPattern.containsMatchIn(hostname) 
    ||      awsPattern.containsMatchIn(hostname) 
    ||        hostname.equals(“onesignal.com”, ignoreCase = true) 
    ||        hostname.equals(“api.braintreegateway.com”, ignoreCase = true) 
    ||        hostname.equals(“payments.braintree-api.com”, ignoreCase = true) 
    ||        hostname.equals(“api.sandbox.braintreegateway.com”, ignoreCase = true) 
    ||        hostname.equals(“payments.sandbox.braintree-api.com”, ignoreCase = true)    }

在第一次尝试后,我们和您一样收到了这条消息:

<块引用>

HostnameVerifier您的应用正在使用不安全的实现 HostnameVerifier 接口。你可以找到更多关于 如何解决这篇 Google 帮助中心文章中的问题。

然后我们求助于“Google 开发/开发人员支持”,询问我们应该怎么做,因为缺乏有关该问题的信息。一周后,我们收到了一条消息,并更好地了解了我们如何找到解决方案而不是在哪里可以找到它。

HostnameVerifier 的脆弱实现:

  • Lf/a/a/a/a/l/e$a;
  • Lf/a/a/a/a/l/f$a;
  • 要正确处理主机名验证,您需要更改自定义 HostnameVerifier 接口中的验证方法,以在服务器主机名不符合您的预期时返回 false。您可以参阅 Play 管理中心的提醒页面以获取更多指导。

暴露的 Google Cloud Platform (GCP) API 密钥。

  • com.onesignal.h2->d 您的应用中公开的 GCP API 密钥的位置可以在您应用的 Play 管理中心通知中找到。您可以参考此帮助中心页面来修复泄露的凭据漏洞问题。

OneSignal 相关信息非常清楚,经过短暂搜索后,我们发现了类似的评论,建议将版本号(从 2.6.1 开始)设置为 onesignal_flutter: 2.6.2。 OneSignal 问题已解决。

说真的,有两个星期的绝望时期,我们找不到任何关于易受攻击的实施问题的东西,也没有“开发者支持”的建议:

<块引用>

“虽然我很乐意回答有关管理您的应用程序的任何问题 在 Google Play 商店中,我们的团队没有接受过提供技术支持的培训 支持应用程序开发问题。寻求帮助开发Android 应用程序,我建议使用我们的 Android 开发者网站。该网站有 技术文档、Android SDK 和分发技巧 你的应用程序。” - GooglePlay 开发者支持。

最终,我们不得不处理与我们使用的插件相关的漏洞问题,并发现了一个 Braintree 问题,该问题建议将版本号设置为 flutter_braintree: 1.1.0+1

在这两个版本号升级(Onesignal、Braintree)之后,没有更多关于 HostameVerifier 问题的消息,一切似乎都很好。

Pubspec.yaml

flutter_html: ^0.11.1
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  http: ^0.12.0+2
  provider: ^4.1.3
  logger: ^0.7.0+2
  shared_preferences: ^0.5.4+6
  json_annotation: ^3.0.0
  flutter_dotenv: ^2.1.0
  flutter_swiper: ^1.1.6
  package_info: ^0.4.0+3
  path_provider: 1.6.24
  get_version: ^0.2.0+1
  uuid: ^2.0.4
  flappy_translator: ^1.2.2
  flutter_circular_chart: ^0.1.0
  percent_indicator: "^2.1.1"
  intl: ^0.16.0
  bezier_chart: ^1.0.15
  charts_flutter: ^0.8.1
  fl_chart: ^0.6.0
  flutter_native_timezone: ^1.0.4
  url_launcher: ^5.7.8
  permission_handler: ^5.0.1+1
  onesignal_flutter: 2.6.2
  flutter_braintree: 1.1.0+1
  after_layout: ^1.0.7+2
  flutter_svg: ^0.19.0
  custom_switch_button: 0.5.0
  wc_flutter_share: ^0.2.2
  esys_flutter_share: ^1.0.2
  just_audio: ^0.5.7
  cached_network_image: 2.2.0+1
  sqflite: ^1.3.1
  cupertino_icons: ^0.1.2
  in_app_purchase: 0.3.4+5

答案 1 :(得分:1)

肯定你有一个类似于这个

的代码
 HostnameVerifier hostnameVerifier = new HostnameVerifier() {
     @Override
     public boolean verify(String hostname, SSLSession session) {
        HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
        return true;
     }
};

或者:

HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier(){ 
                public boolean verify(String hostname, SSLSession session) { 
                        return true; 
                }}); 

替换为:

 HostnameVerifier hostnameVerifier = new HostnameVerifier() {
     @Override
     public boolean verify(String hostname, SSLSession session) {
        HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
        if(myHostNameToVerify==hostname || myOtherHostNameToVerify == hostname) {

            return true;
        } else {
            return false;
        }
     }
};

或者:

HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier(){ 
                public boolean verify(String hostname, SSLSession session) { 
                        if(myHostNameToVerify==hostname || 
                           myOtherHostNameToVerify == hostname) {

                             return true;
                        } else {
                             return false;
                        }
                }}); 

如果您使用SSL验证程序,我建议添加与此类似的代码:

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

Google从2016年中期到2017年初需要更安全的代码。