安全的用户身份验证

为了保护您在 Android 中的身份验证系统,不妨考虑弃用 基于密码的模型,尤其是敏感账号,例如用户银行 和电子邮件账号。请注意,您的用户安装的某些应用可能没有 最佳意图,并且可能会试图骗取用户。

此外,请勿假设只有获得授权的用户才能使用设备。手机盗窃 是一个常见问题,攻击者通过锁定未锁定设备来直接盈利 收集用户数据或金融应用的数据我们建议所有敏感应用都实施 合理的身份验证超时(15 分钟?), 要求在执行敏感操作(如金钱)之前进行额外身份验证 传输。

生物识别身份验证对话框

Biometrics 库提供了一组函数,用于显示请求 生物识别身份验证,例如人脸识别或指纹识别。 不过,生物识别提示可以配置为回退到 LSKF,它具有 已知的路边冲浪风险。对于敏感应用,我们建议 没有使用生物识别信息回退到 PIN 码,并且在用尽生物识别验证方式后, 用户可以等待,也可以使用密码重新登录或重置账号。账号已重置 应要求提供难以在设备上访问的因素(最佳做法 )。

这些信息如何帮助防范欺诈和手机盗窃

有助于防止欺诈的一个具体用例是 在您的应用内进行生物识别身份验证。当您的用户 进行财务交易时,系统会显示生物识别对话框 验证确实是进行交易的目标用户。这个 最佳做法是防止攻击者窃取设备 因为他们需要探测是否知道 LSKF 设备所有者

为了提高安全性,我们建议应用开发者申请第 3 类 生物识别身份验证,并使用 CryptoObject 进行银行业务和 金融交易。

实现

  1. 确保包含 androidx.biometric 库。
  2. 在存储的 activity 或 fragment 中添加生物识别登录对话框 您希望对用户进行身份验证的逻辑。

Kotlin


private var executor: Executor? = null
private var biometricPrompt: BiometricPrompt? = null
private var promptInfo: BiometricPrompt.PromptInfo? = null

fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_login)
  executor = ContextCompat.getMainExecutor(this)
  biometricPrompt = BiometricPrompt(this@MainActivity,
    executor, object : AuthenticationCallback() {
      fun onAuthenticationError(
        errorCode: Int,
        @NonNull errString: CharSequence
      ) {
        super.onAuthenticationError(errorCode, errString)
        Toast.makeText(
          getApplicationContext(),
          "Authentication error: $errString", Toast.LENGTH_SHORT
        )
          .show()
      }

      fun onAuthenticationSucceeded(
        @NonNull result: BiometricPrompt.AuthenticationResult?
      ) {
        super.onAuthenticationSucceeded(result)
        Toast.makeText(
          getApplicationContext(),
          "Authentication succeeded!", Toast.LENGTH_SHORT
        ).show()
      }

      fun onAuthenticationFailed() {
        super.onAuthenticationFailed()
        Toast.makeText(
          getApplicationContext(), "Authentication failed",
          Toast.LENGTH_SHORT
        )
          .show()
      }
    })
  promptInfo = Builder()
    .setTitle("Biometric login for my app")
    .setSubtitle("Log in using your biometric credential")
    .setNegativeButtonText("Use account password")
    .build()

  // Prompt appears when user clicks "Log in".
  // Consider integrating with the keystore to unlock cryptographic operations,
  // if needed by your app.
  val biometricLoginButton: Button = findViewById(R.id.biometric_login)
  biometricLoginButton.setOnClickListener { view ->
    biometricPrompt.authenticate(
      promptInfo
    )
  }
}

Java


private Executor executor;
private BiometricPrompt biometricPrompt;
private BiometricPrompt.PromptInfo promptInfo;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_login);
    executor = ContextCompat.getMainExecutor(this);
    biometricPrompt = new BiometricPrompt(MainActivity.this,
            executor, new BiometricPrompt.AuthenticationCallback() {
        @Override
        public void onAuthenticationError(int errorCode,
                @NonNull CharSequence errString) {
            super.onAuthenticationError(errorCode, errString);
            Toast.makeText(getApplicationContext(),
                "Authentication error: " + errString, Toast.LENGTH_SHORT)
                .show();
        }

        @Override
        public void onAuthenticationSucceeded(
                @NonNull BiometricPrompt.AuthenticationResult result) {
            super.onAuthenticationSucceeded(result);
            Toast.makeText(getApplicationContext(),
                "Authentication succeeded!", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onAuthenticationFailed() {
            super.onAuthenticationFailed();
            Toast.makeText(getApplicationContext(), "Authentication failed",
                Toast.LENGTH_SHORT)
                .show();
        }
    });

    promptInfo = new BiometricPrompt.PromptInfo.Builder()
            .setTitle("Biometric login for my app")
            .setSubtitle("Log in using your biometric credential")
            .setNegativeButtonText("Use account password")
            .build();

    // Prompt appears when the user clicks "Log in".
    // Consider integrating with the keystore to unlock cryptographic operations,
    // if needed by your app.
    Button biometricLoginButton = findViewById(R.id.biometric_login);
    biometricLoginButton.setOnClickListener(view -> {
            biometricPrompt.authenticate(promptInfo);
    });
}

最佳做法

我们建议您从 Codelab 开始,详细了解生物识别。

根据您的用例,您可以选择是否实现对话框 。为避免欺诈,建议您添加生物识别信息 包含每个交易的明确用户操作的对话框。我们知道 添加身份验证会给用户体验带来不便,但由于 银行交易中处理的信息以及 比其他身份验证方法更流畅,我们认为 添加这一级别的导航所必需的操作。

详细了解生物识别身份验证

通行密钥

通行密钥是一种更安全、更简便的替代密码。通行密钥的用途 公钥加密,可让用户登录应用和网站 使用设备的屏幕锁定机制(例如指纹或人脸) 识别。这让用户不必记住和管理密码 并可显著提升安全性。

通行密钥只需一步即可满足多重身份验证要求 替换密码和动态密码,从而提供针对 钓鱼式攻击,避免用户通过短信或一次性使用应用带来的痛苦 密码。由于通行密钥是标准化的,因此只需实现一次即可 为所有用户提供无密码登录体验设备、浏览器和 操作系统

在 Android 上,使用 Credential Manager Jetpack 支持通行密钥 这个库统一了主要的身份验证方法,包括通行密钥、 密码和联合登录(例如“使用 Google 账号登录”功能)。

这些信息如何帮助防范欺诈行为

通行密钥可保护您免受钓鱼式攻击,因为它们仅对您的 。

通行密钥的核心组件是加密私钥。通常情况下, 私钥仅存放在您的设备,如笔记本电脑或手机, 并通过凭据提供程序(也称为密码) 密码管理工具,例如 Google 密码管理工具。只有相应的公钥 在创建通行密钥时由在线服务保存。登录期间,该服务 使用私钥对来自公钥的质询进行签名。这只能 来自您的某部设备此外,要实现这一目的 解锁设备或凭据存储区,这样可以防止未经授权的登录 (例如,手机被盗)。

为防止在设备被盗、解锁后遭到未经授权的访问, 必须搭配合理的身份验证超时窗口。一个 窃取设备的攻击者不应该只使用应用, 因为之前的用户已经登录。相反,凭据应 定期到期(如每 15 分钟一次),用户应 重新验证身份。

如果您的手机被盗,通行密钥可以为您保驾护航,因为盗窃者无法窃取您的 可在其他设备上使用的密码,通行密钥因设备而异。如果您使用 使用 Google 密码管理工具,而您的手机被盗,您可以登录自己的 Google 从其他设备(如计算机)登录,然后远程退出 手机被盗这会在被盗手机上启用 Google 密码管理工具 无法使用,包括任何已保存的通行密钥。

在最糟糕的情况下,如果被盗设备未恢复,那么通行密钥会 由创建和同步的凭据提供商同步回新设备 通行密钥例如,用户可能选择了 Google 密码管理工具 创建通行密钥,而且可以在新设备上通过在 Google 上 用户的 Google 账号,并提供之前的 设备。

如需了解详情,请参阅 Google 密码管理工具中通行密钥的安全性一文。

实现

搭载 Android 9(API 级别 28)或更高版本的设备支持通行密钥。 Android 4.4 及更高版本支持密码和“使用 Google 账号登录”功能。接收者 若要开始使用通行密钥,请按以下步骤操作:

  1. 学习 Credential Manager Codelab,初步了解如何实现通行密钥。
  2. 查看通行密钥用户体验设计指南。本文档介绍了针对您的使用场景推荐的流程。
  3. 按照指南学习 Credential Manager。
  4. 为您的应用规划 Credential Manager 和通行密钥实现。计划添加对 Digital Asset Links 的支持。

请参阅我们的开发者文档,详细了解如何创建、注册和 使用通行密钥进行身份验证

安全账号重置

未经授权的攻击者使用已解锁的设备(例如,手机 )会尝试访问敏感应用,尤其是银行应用或现金应用。 如果应用实现了生物识别验证,攻击者会尝试重置 登录该账号账号重置流程不仅仅依靠 设备上易于访问的信息(例如电子邮件或短信动态密码) 重置链接。

以下是一些可以在应用重置过程中采用的常见最佳实践 流程:

  • 除动态密码外的人脸识别
  • 安全问题
  • 知识因素(例如母亲的婚前姓氏、出生城市或收藏地点) 歌曲)
  • 身份证件验证

SMS Retriever API

通过 SMS Retriever API,您可以在自己的 Android 应用。这样,用户就无需 手动输入验证码。此外,此 API 不会询问用户 获取额外的可能危险的应用权限,例如 RECEIVE_SMSREAD_SMS。但是,短信不应用作唯一的用户验证方式, 防止设备遭到未经授权的本地访问。

这些信息如何帮助防范欺诈行为

有些用户使用短信验证码作为唯一的身份验证方法, 轻松防范欺诈

SMS Retriever API 允许应用直接检索短信代码,而无需 用户互动,并且可以在一定程度上防范欺诈。

实现

实现 SMS Retriever API 的过程分为两个部分:Android 和 Server。

Android:(指南

  1. 获取用户的电话号码。
  2. 启动短信检索器客户端。
  3. 将电话号码发送到您的服务器。
  4. 接收验证邮件。
  5. 将动态密码发送至您的服务器。

服务器:(指南

  1. 构建验证消息。
  2. 通过短信发送验证消息。
  3. 验证系统返回的动态密码。

最佳做法

应用集成并且用户的电话号码通过 SMS Retriever API 的调用时,它会尝试获取动态密码。如果成功了 表明设备自动收到了短信。如果没有 并且用户需要手动输入动态密码,这可能是一个警告标志 用户可能存在欺诈行为。

短信会留出空间,因此不应将短信用作唯一的用户验证机制 本地攻击,例如盗窃已解锁设备的攻击者;或 SIM 卡 克隆攻击建议尽可能使用生物识别。已开启 生物识别传感器不可用的设备,应进行用户身份验证 依赖至少一个很难从当前设备获取的因素。

了解详情

如需详细了解最佳实践,请查看以下资源: