Android Bad Practices: Missing Google Play Services Updated Security Provider

Android 程序的安全检测,检测到的漏洞。
解释:
应用程序不使用 Google Play 服务更新的安全提供程序,这可能使其未来易遭受 OpenSSL 库中漏洞的攻击。
Android 依赖于可提供安全网络通信的安全提供程序。 但是,有时漏洞存在于默认安全提供程序中。 为了防 范这些漏洞,Google Play 服务可提供用于自动更新设备安全提供程序的方法,以防御已知盗取手段。 通过调用 Google Play 服务方法,您的应用程序可以确保其在具有最新更新的设备上运行,以防御已知盗取手段。
解决方法:

使用 ProviderInstaller 为安全提供程序打补丁

如需更新设备的安全提供程序,请使用 ProviderInstaller 类。通过调用该类的 installIfNeeded()(或 installIfNeededAsync())方法,您可以验证安全提供程序是否处于最新状态(如果需要,请对其进行更新)。

当您调用 installIfNeeded() 时,ProviderInstaller 将执行以下操作:

  • 如果设备的 Provider 已成功更新(或者已经处于最新状态),此方法将正常返回。
  • 如果设备的 Google Play 服务库已过期,此方法会抛出 GooglePlayServicesRepairableException。然后,应用可以捕获此异常,并向用户显示相应的对话框以更新 Google Play 服务。
  • 如果出现不可恢复的错误,此方法将抛出 GooglePlayServicesNotAvailableException 以表明它无法更新 Provider。然后,应用可以捕获异常,并选择相应的操作,例如显示标准的修复流程图

installIfNeededAsync() 方法的行为方式与之相似,只是不会抛出异常,而是会调用相应的回调方法以表明更新成功还是失败。

如果 installIfNeeded() 需要安装新的 Provider,所需的时间从 30-50 毫秒(在较新的设备上)到 350 毫秒(在较旧的设备上)不等。如果安全提供程序已经处于最新状态,该方法需要的时间微不足道。为避免影响用户体验,请执行以下操作:

  • 在加载线程时立即从后台网络线程调用 installIfNeeded(),而不是等待线程尝试使用网络。(多次调用该方法没有任何坏处,因为如果安全提供程序不需要更新,它会立即返回。)
  • 如果用户体验受线程拦截影响(例如,如果调用来自界面线程中的某个 Activity),请调用此方法的异步版本,即 installIfNeededAsync()。(当然,如果执行此操作,您需要等待操作完成后再尝试任何安全的通信。ProviderInstaller 会调用侦听器的 onProviderInstalled() 方法以指示成功。)
  • 在更新 Provider 后,对安全 API(包括 SSL API)的所有调用均通过它进行路由。(但是,这不适用于 android.net.SSLCertificateSocketFactory,其仍然容易受到类似 CVE-2014-0224 的攻击。)

​​​​​​​解决方法有两种:1,同步打补丁

为安全提供程序打补丁的最简单方法是调用同步方法 installIfNeeded()。如果在等待操作完成时用户体验不会受到线程拦截影响,该方法会非常适用。

例如,下面是一个可以更新安全提供程序的同步适配器的实现。由于同步适配器在后台运行,因此,如果正在等待安全提供程序更新,线程就可以实施拦截。同步适配器将调用 installIfNeeded() 以更新安全提供程序。如果该方法正常返回,同步适配器会知道安全提供程序处于最新状态。如果该方法引发异常,则同步适配器可以进行适当的操作(例如提示用户更新 Google Play 服务)。

    /**
     * Sample sync adapter using {@link ProviderInstaller}.
     */
    public class SyncAdapter extends AbstractThreadedSyncAdapter {

      ...

      // This is called each time a sync is attempted; this is okay, since the
      // overhead is negligible if the security provider is up-to-date.
      @Override
      public void onPerformSync(Account account, Bundle extras, String authority,
          ContentProviderClient provider, SyncResult syncResult) {
        try {
          ProviderInstaller.installIfNeeded(getContext());
        } catch (GooglePlayServicesRepairableException e) {

          // Indicates that Google Play services is out of date, disabled, etc.

          // Prompt the user to install/update/enable Google Play services.
          GoogleApiAvailability.getInstance()
                  .showErrorNotification(context, e.connectionStatusCode)

          // Notify the SyncManager that a soft error occurred.
          syncResult.stats.numIoExceptions++;
          return;

        } catch (GooglePlayServicesNotAvailableException e) {
          // Indicates a non-recoverable error; the ProviderInstaller is not able
          // to install an up-to-date Provider.

          // Notify the SyncManager that a hard error occurred.
          syncResult.stats.numAuthExceptions++;
          return;
        }

        // If this is reached, you know that the provider was already up-to-date,
        // or was successfully updated.
      }
    }
    

2.异步打补丁

更新安全提供程序最多需要 350 毫秒的时间(在较旧的设备上)。如果在直接影响用户体验的线程(例如界面线程)上进行更新,您一定不希望通过同步调用更新提供程序,因为这会导致应用或设备在相应操作完成前处于冻结状态。相反,您应该使用异步方法 installIfNeededAsync()。该方法通过调用回调指示其成功还是失败。

例如,下面是可以在界面线程的某个 Activity 中更新安全提供程序的一些代码。此 Activity 会调用 installIfNeededAsync() 以更新提供程序,并将自身指定为接收成功或失败通知的侦听器。如果安全提供程序为最新或已成功更新,将调用此 Activity 的 onProviderInstalled() 方法,且 Activity 知道通信是安全的。如果提供程序无法更新,将调用此 Activity 的 onProviderInstallFailed() 方法,且 Activity 可以进行适当的操作(如提示用户更新 Google Play 服务)。

    /**
     * Sample activity using {@link ProviderInstaller}.
     */
    public class MainActivity extends Activity
        implements ProviderInstaller.ProviderInstallListener {

      private static final int ERROR_DIALOG_REQUEST_CODE = 1;

      private boolean retryProviderInstall;

      //Update the security provider when the activity is created.
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ProviderInstaller.installIfNeededAsync(this, this);
      }

      /**
       * This method is only called if the provider is successfully updated
       * (or is already up-to-date).
       */
      @Override
      protected void onProviderInstalled() {
        // Provider is up-to-date, app can make secure network calls.
      }

      /**
       * This method is called if updating fails; the error code indicates
       * whether the error is recoverable.
       */
      @Override
      protected void onProviderInstallFailed(int errorCode, Intent recoveryIntent) {
        GoogleApiAvailability availability = GoogleApiAvailability.getInstance();
        if (availability.isUserRecoverableError(errorCode)) {
          // Recoverable error. Show a dialog prompting the user to
          // install/update/enable Google Play services.
          availability.showErrorDialogFragment(
              this,
              errorCode,
              ERROR_DIALOG_REQUEST_CODE,
              new DialogInterface.OnCancelListener() {
                @Override
                public void onCancel(DialogInterface dialog) {
                  // The user chose not to take the recovery action
                  onProviderInstallerNotAvailable();
                }
              });
        } else {
          // Google Play services is not available.
          onProviderInstallerNotAvailable();
        }
      }

      @Override
      protected void onActivityResult(int requestCode, int resultCode,
          Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == ERROR_DIALOG_REQUEST_CODE) {
          // Adding a fragment via GoogleApiAvailability.showErrorDialogFragment
          // before the instance state is restored throws an error. So instead,
          // set a flag here, which will cause the fragment to delay until
          // onPostResume.
          retryProviderInstall = true;
        }
      }

      /**
       * On resume, check to see if we flagged that we need to reinstall the
       * provider.
       */
      @Override
      protected void onPostResume() {
        super.onPostResume();
        if (retryProviderInstall) {
          // We can now safely retry installation.
          ProviderInstaller.installIfNeededAsync(this, this);
        }
        retryProviderInstall = false;
      }

      private void onProviderInstallerNotAvailable() {
        // This is reached if the provider cannot be updated for some reason.
        // App should consider all HTTP communication to be vulnerable, and take
        // appropriate action.
      }
    }
    

需要引用

implementation 'com.google.android.gms:play-services-safetynet:15.0.1'
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
《数字设计:原理与实践(含Verilog),第5版》是一本经典教材,它介绍了数字设计的基本原理和实践技巧,并深入讲解了Verilog语言的应用。 首先,该教材系统地介绍了数字电路设计的基本概念和原理,包括数字信号处理、逻辑门电路、时序电路、摩尔定律等。读者可以从中了解到数字设计的基本过程和设计思想,并能够理解数字电路的构成和工作原理。 其次,该教材详细介绍了Verilog语言的使用方法和基本语法规则。Verilog是一种用于数字系统设计和模拟的硬件描述语言,通过学习Verilog,读者可以掌握数字系统建模和验证的技巧,并能够使用Verilog语言进行实际的数字电路设计。 此外,教材还包含了丰富的实例和案例,通过这些案例,读者可以学习到如何使用Verilog语言进行数字电路的设计和仿真。同时,案例中还提供了详细的设计说明和实验步骤,帮助读者深入了解数字设计的实践过程。 该教材不仅适合作为高等院校的教材,也适合作为工程师和设计师的参考书。无论是初学者还是有一定经验的读者,都能从中获得有关数字设计和Verilog语言的宝贵知识。另外,本书的第5版还更新了一些内容,使其更加符合当前数字设计和Verilog语言的发展趋势。 总之,《数字设计:原理与实践(含Verilog),第5版》是一本全面介绍数字设计原理和实践的教材,它通过深入讲解数字设计的基本原理和Verilog语言的应用,帮助读者掌握数字电路设计的基本技巧,提高数字系统设计和验证的能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值