配置多重身份验证

本页介绍了如何配置多重身份验证 (MFA),以便通过电子邮件或短信发送验证码来验证用户的身份。使用此功能,您可以验证用户是否拥有与其帐号关联的电子邮件地址或电话号码。MFA 有助于保护您的用户免受凭据填充攻击和帐号盗用 (ATO) 攻击。

MFA 仅适用于基于得分的网站密钥,不适用于复选框网站密钥。

了解 MFA 的配置过程

如需配置 MFA,请按以下步骤操作:

  1. 检测客户端上的关键工作流(登录、注册等)
  2. 请求并解读评估中的 MFA 信息
  3. 在客户端上触发 MFA 挑战
  4. 请求重新评估,以确保成功验证用户的电子邮件地址或电话号码。

准备工作

  1. 选择在您的环境中设置 reCAPTCHA Enterprise 的最佳方法,并完成设置。

  2. 安全审核后,可访问 MFA。请与我们的销售团队联系,在您的网站上启用此功能。 向销售团队提供以下初始配置信息:

    • Google Cloud 项目编号
    • 要初始配置的网站密钥
    • 平均 QPS(每秒发送的电子邮件/短信数)
    • QPS 峰值(每秒发送的电子邮件/短信数)
    • 对于电子邮件 MFA,您在测试期间所需的发件人地址、电子邮件地址或域名
    • 对于短信 MFA,每个目的地国家/地区(您的用户所在的国家/地区)的峰值和平均 QPS
  3. 按照针对具体平台的说明,在您希望启用 MFA 的平台上集成 reCAPTCHA Enterprise:

检测客户端上的关键工作流

通过 execute() 函数将必要的信息传递给 reCAPTCHA Enterprise,以用于风险评估。execute() 函数返回生成令牌时解析的 promise。

网站

execute() 函数附加另一个 twofactor 参数,如以下示例代码所示:

grecaptcha.enterprise.execute(SITE_KEY, {
  action: 'login',
  twofactor: true
}).then(token => {
  /// Handle the generated token.
});

Android

按照为您的 Android 应用生成令牌的说明执行操作。不需要其他参数。

iOS

按照为您的 iOS 应用生成令牌的说明执行操作。不需要其他参数。

请求评估

借助通过 execute() 函数生成的令牌,使用 reCAPTCHA Enterprise 客户端库gcloud 命令行工具进行身份验证,以发出评估请求。

提供经过哈希处理的帐号标识符以及一个或多个端点(例如电子邮件地址和电话号码),在评估中进行验证。经过哈希处理的帐号标识符是您的网站专属的用户帐号的匿名永久性标识符。使用稳定帐号标识符的单向哈希。我们建议将 sha256-hmac 结合不与我们共享的稳定密钥使用。

{
  "event": {
    "token": "token",
    "siteKey": "key",
    "hashedAccountId": "BP3ptt00D9W7UMzFmsPdEjNH3Chpi8bo40R6YW2b"
  },
  "accountVerification": {
    "endpoints": [{
      "emailAddress": "foo@bar.com",
    },
    {
      "phoneNumber": "+11111111111",
    }]
  }
}

如果与该功能的集成成功,则评估必须包含与 MFA 相关的更多信息,如以下示例所示:

{
  [...],
  "accountVerification": {
    "endpoints": [{
      "emailAddress": "foo@bar.com",
      "requestToken": "tplIUFvvJUIpLaOH0hIVj2H71t5Z9mDK2RhB1SAGSIUOgOIsBv",
      "lastVerificationTime": "",
    },
    {
      "phoneNumber": "+11111111111",
      "requestToken": "fwdgk0kcg1W0mbpetYlgTZKyrp4IHKzjgRkb6vLNZeBQhWdR3a",
      "lastVerificationTime": "",
    }],
    "latestVerificationResult": "RESULT_UNSPECIFIED"
  }
}

评估将包括设备上发布令牌的给定端点最近一次成功验证的日期和时间(如果有的话)。它还为每个端点包含一个 requestToken 字段,其中包含一个加密字符串。如果您决定触发该端点的 MFA 挑战,则必须将此加密的字符串发送回客户端。请求令牌的有效期为 15 分钟。

在客户端上触发 MFA 挑战

如果您已决定根据评估中所包含的信息挑战用户,则请将您要验证的端点的 MFA 请求令牌从评估发送回客户端。要触发 MFA 挑战,需要使用此请求令牌。

调用 challengeAccount() 来触发 MFA 挑战。challengeAccount() 函数返回一个在挑战完成后被解析或在出现错误或超时时被拒绝的 promise。完成后,系统会生成包含更新信息的新令牌,然后发送该令牌进行评估。

网站

通过调用 challengeAccount() 函数触发 MFA 挑战,如以下示例所示。

请提供以下值:

  • REQUEST_TOKEN_FROM_ASSESSMENT:评估响应中的 requestToken 字段的值。
  • CONTAINER_HTML_COMPONENT_ID:必须在其中呈现验证挑战的 HTML 组件的 ID。 如果您未指定此参数,则挑战会呈现在页面顶部的叠加层中。
grecaptcha.enterprise.challengeAccount(SITE_KEY, {
  'account-token': REQUEST_TOKEN_FROM_ASSESSMENT,
  'container': CONTAINER_HTML_COMPONENT_ID
}).then(newToken => {
  // Handle the new token.
});

Android

通过从应用中的 Context 调用 challengeAccount() 来触发 MFA 挑战。

Recaptcha.getClient(this)
   .challengeAccount(recaptchaHandle, requestToken)
   .addOnSuccessListener(
       this,
       new OnSuccessListener<VerificationHandle>() {
         @Override
         public void onSuccess(VerificationHandle handle) {
           VerificationHandle verificationHandle = handle;
           // Handle success ...
         }
       })
   .addOnFailureListener(
       this,
       new OnFailureListener() {
         @Override
         public void onFailure(@NonNull Exception e) {
           if (e instanceof ApiException) {
              ApiException apiException = (ApiException) e;
              Status apiErrorStatus = apiException.getStatusCode();
              // Handle API errors ...
           } else {
              // Handle other failures ...
           }

         }
       });

从用户那里获得 PIN 后,请从应用中的 Activity 调用 verifyAccount(),以验证输入 PIN 码是否正确。

Recaptcha.getClient(this)
   .verifyAccount("userProvidedPIN", recaptchaHandle)
   .addOnSuccessListener(
       this,
       new OnSuccessListener<VerificationResult>() {
         @Override
         public void onSuccess(VerificationResult result) {
           if (result.getVerificationStatus().isSuccess()) {
             String recaptchaToken = result.recaptchaToken().orNull()
             // Handle success ...
           } else {
             VerificationHandle verificationHandle =
                              result.verificationHandle().orNull();
             Status errorStatus = result.getVerificationStatus();
             // Handle retries ...
           }
         }
       })
   .addOnFailureListener(
       this,
       new OnFailureListener() {
         @Override
         public void onFailure(@NonNull Exception e) {
           if (e instanceof ApiException) {
              ApiException apiException = (ApiException) e;
              Status apiErrorStatus = apiException.getStatusCode();
              // Handle API errors ...
           } else {
              // Handle other failures ...
           }
         }
       });

iOS

调用 challengeAccount() 来触发 MFA 挑战。

recaptchaClient.challengeAccount(withRequestToken: "Request Token").then { verificationHandler in
  // Show your UI and retrieve the pin from the user.
}.catch { error in
  // Handle error.
}

从用户获取 PIN 码后,请调用 verificationHandler 对象的 verifyPin() 方法以完成验证。

handler.verifyPin("PIN") { recaptchaToken, recaptchaError in
  // Handle token/error.
}

请求新评估

通过经过哈希处理的帐号标识符和 endpoints 字段请求新的评估。

在客户端完成工作流后,您将获得一个新令牌,可以用来获取触发的验证结果。此评估包含有关最新成功验证的最近时间戳,以及成功结果状态。

以下示例显示了一个使用从客户端获得的新令牌请求新评估时收到的示例评估。

{
  [...],
  "accountVerification": {
    "endpoints": [{
      "emailAddress": "foo@bar.com",
      "requestToken": "tplIUFvvJUIpLaOH0hIVj2H71t5Z9mDK2RhB1SAGSIUOgOIsBv",
      "lastVerificationTime": "2020-03-23 08:27:12 PST",
    }],
    "latestVerificationResult": "SUCCESS_USER_VERIFIED"
  }
}

字段 latestVerificationResult 可以显示如下表中列出的不同的状态:

验证结果状态 说明
SUCCESS_USER_VERIFIED 已成功验证用户。
ERROR_USER_NOT_VERIFIED 用户未通过验证挑战。
ERROR_SITE_ONBOARDING_INCOMPLETE 您的网站未正确配置,因此无法使用此功能。
ERROR_RECIPIENT_NOT_ALLOWED 此收件人未获准向其发送短信或电子邮件(仅在测试期间)。
ERROR_RECIPIENT_ABUSE_LIMIT_EXHAUSTED 此收件人短时间内收到了过多的验证码。
ERROR_CUSTOMER_QUOTA_EXHAUSTED 您已超出可用的 MFA 配额。
ERROR_CRITICAL_INTERNAL 由于我们的系统出现内部错误,因此未完成验证。
RESULT_UNSPECIFIED 没有与最新验证相关的信息(从未验证)。