检测并防范移动应用中的与账号相关的欺诈活动

本文档介绍了如何使用 reCAPTCHA 账号卫士在移动应用中检测和防范与账号相关的欺诈活动。

reCAPTCHA 可帮助您保护关键操作,例如登录和结账。不过,通过观察特定用户在一段时间内在移动应用中的行为,可以检测到许多细微的账号滥用行为。reCAPTCHA 账号卫士会为您的移动应用创建特定于网站的模型,以检测可疑行为的趋势或活动变化,从而帮助您识别此类细微滥用行为。通过使用特定于网站的模型,reCAPTCHA 账号卫士可帮助您检测以下内容:

  • 可疑活动
  • 具有类似行为的账号
  • 特定用户标记为可信的设备发出的请求

根据 reCAPTCHA 账号卫士的分析和特定于网站的模型,您可以执行以下操作:

  • 限制或停用欺诈性账号。
  • 防止账号盗用尝试。
  • 减少账号盗用成功的几率。
  • 仅向来自合法用户账号的请求授予访问权限。
  • 降低用户从其某部可信设备登录时遇到的阻碍。

准备工作

  1. 向项目添加结算账号后,系统会触发自动安全审核,审核完成后,您就可以使用适用于移动应用的 reCAPTCHA 账号保护程序了。 向您的项目 添加结算账号 ,以便在您的网站上启用此功能。
  2. 为 reCAPTCHA 准备环境
  3. 创建基于得分的键

为移动应用配置 reCAPTCHA 账号卫士

reCAPTCHA 账号卫士需要全面了解账号活动,才能有效检测。如需开始向 reCAPTCHA 账号卫士提交与账号相关的活动,以及创建和改进特定于您网站的模型,请执行以下操作:

  1. 将 reCAPTCHA 与您的移动应用集成。

  2. 报告关键用户操作
  3. 评估关键用户事件
  4. 为用户事件添加注释,以调整特定于您网站的模型

报告关键用户操作

为了检测可疑活动模式并更好地了解您网站上的典型活动模式,reCAPTCHA 账号防护工具需要关键用户操作的相关信息。 对于应用中使用 reCAPTCHA 保护的每项操作,请使用 RecaptchaAction 调用 execute() 方法。如需详细了解 execute()RecaptchaAction,请参阅以下内容:

reCAPTCHA 提供了一组内置操作,您也可以根据需要创建自定义操作。

下表列出了您在报告重要用户操作时可以使用的操作名称。

操作名称 用户发起的事件或用户操作
LOGIN

登录移动应用。

SIGNUP

在移动应用中注册。

评估关键用户事件

当您对用户操作调用 execute() 时,它会生成令牌。对于关键用户事件(例如登录成功和失败、注册以及已登录用户的操作),请创建评估来评估 execute() 调用的结果。该评估会提供风险判定结果,以便您据此决定如何处理可能存在欺诈行为的活动。您可以采取的一些措施包括屏蔽可疑请求、质疑有风险的登录行为,以及调查感兴趣的账号。

reCAPTCHA 账号防护工具要求您提供稳定的账号标识符,以将用户活动(例如登录请求、已登录请求和注册请求)归因于特定账号。这有助于 reCAPTCHA 账号卫士了解用户活动模式,并为每个账号构建活动模型,以便更好地检测异常流量和滥用流量。

选择一个稳定的账号标识符 accountId(用户不经常更改),并在 projects.assessments.create 方法中将其提供给评估。与同一用户相关的所有事件都应具有相同的稳定账号标识符值。您可以提供以下账号标识符:

用户标识符

如果每个账号都可以与稳定的用户名、电子邮件地址或手机号码进行唯一关联,您可以将其用作 accountId。当您提供此类跨网站标识符(可在多个网站中重复使用的标识符)时,reCAPTCHA 会使用这些信息,通过标记滥用账号标识符并利用与这些标识符相关的跨网站滥用行为模式知识,根据跨网站模型加强对用户账号的保护。

或者,如果您有与每个账号唯一关联的内部用户 ID,则可以将其作为 accountId 提供。

经过哈希处理或加密

如果您没有与每个账号唯一关联的内部用户 ID,则可以将任何稳定标识符转换为不透明的网站专用账号标识符。reCAPTCHA 账号卫士仍需要此标识符来了解用户活动模式并检测异常行为,但不会将其分享给其他网站。

选择任何稳定的账号标识符,并使用加密或哈希处理使其不透明,然后再发送到 reCAPTCHA:

  • 加密(推荐):使用可生成稳定密文的确定性加密方法对账号标识符进行加密。如需了解详细说明,请参阅确定性地加密数据。如果您选择对称加密而非哈希处理,则无需在用户标识符与相应的不透明用户标识符之间保持映射。 解密 reCAPTCHA 返回的不透明标识符,将其转换为用户标识符。

  • 哈希处理:我们建议使用 SHA256-HMAC 方法和您选择的自定义盐对账号标识符进行哈希处理。由于哈希值是单向的,因此您需要在生成的哈希值和用户标识符之间保持映射,以便将返回的经过哈希处理的账号标识符映射回原始账号。

除了为所有与账号相关的请求提供稳定的账号标识符外,您还可以为某些特定请求提供其他账号标识符(可能不稳定)。 除了 accountId 之外,提供的情境特定账号标识符有助于 reCAPTCHA 账号卫士更好地了解用户活动并检测账号盗用企图,从而保障您的用户账号安全。当您提供其他标识符时,reCAPTCHA 会使用这些信息来标记滥用账号标识符,并利用与这些标识符相关的跨网站滥用行为模式知识,根据跨网站模型加强对用户账号的保护。例如,您可以提供以下信息:

  • 作为登录请求的登录标识名使用的用户名、电子邮件地址或手机号码

  • 用于多重身份验证请求的已验证电子邮件地址或手机号码

  • 用户在请求更新账号时提供的电子邮件地址或手机号码(主号码或辅助号码)

  • 用户在注册请求期间提供的电子邮件地址和手机号码

对于所有与账号相关的请求,将所选的稳定账号标识符附加到 projects.assessments.create 方法中的 accountId 参数。(可选)您可以使用评估中的 userIds 字段,为相关请求提供其他账号标识符。

在使用任何请求数据之前,请先进行以下替换:

  • PROJECT_ID:您的 Google Cloud 项目 ID
  • TOKEN:从 execute() 调用返回的令牌
  • KEY_ID:与应用关联的 reCAPTCHA 密钥
  • ACCOUNT_ID:与应用用户账号的用户账号唯一相关联的标识符
  • EMAIL_ADDRESS:可选。与此请求关联的电子邮件地址(如果有)
  • PHONE_NUMBER:可选。与此请求关联的手机号码(如果有)
  • USERNAME:可选。与此请求关联的用户名(如果有)

HTTP 方法和网址:

POST https://recaptchaenterprise.googleapis.com/v1/projects/PROJECT_ID/assessments

请求 JSON 正文:

{
  "event": {
    "token": "TOKEN",
    "siteKey": "KEY_ID",
    "userInfo": {
      "accountId": "ACCOUNT_ID",
      "userIds": [
        {
          "email": "EMAIL_ADDRESS"
        },
        {
          "phoneNumber": "PHONE_NUMBER"
        },
        {
          "username": "USERNAME"
        }
      ]
    }
  }
}

如需发送请求,请选择以下方式之一:

curl

将请求正文保存在名为 request.json 的文件中,然后执行以下命令:

curl -X POST \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json; charset=utf-8" \
-d @request.json \
"https://recaptchaenterprise.googleapis.com/v1/projects/PROJECT_ID/assessments"

PowerShell

将请求正文保存在名为 request.json 的文件中,然后执行以下命令:

$cred = gcloud auth print-access-token
$headers = @{ "Authorization" = "Bearer $cred" }

Invoke-WebRequest `
-Method POST `
-Headers $headers `
-ContentType: "application/json; charset=utf-8" `
-InFile request.json `
-Uri "https://recaptchaenterprise.googleapis.com/v1/projects/PROJECT_ID/assessments" | Select-Object -Expand Content

您应该收到类似以下内容的 JSON 响应:

{
  "tokenProperties": {
    "valid": true,
    "androidPackageName": "com.example.app" or "iosBundleId": "com.example.app",
    "action": "login",
    "createTime": "2019-03-28T12:24:17.894Z"
   },
  "riskAnalysis": {
    "score": 0.6,
  },
 "event": {
    "token": "TOKEN",
    "siteKey": "KEY",
    "userInfo": {
      "accountId": "ACCOUNT_ID"
    }
  },
  "name": "projects/PROJECT_NUMBER/assessments/b6ac310000000000",
  "accountDefenderAssessment": {
    "labels": ["SUSPICIOUS_LOGIN_ACTIVITY"]
  }
}

代码示例

Java

如需向 reCAPTCHA 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅为本地开发环境设置身份验证


import com.google.cloud.recaptchaenterprise.v1.RecaptchaEnterpriseServiceClient;
import com.google.protobuf.ByteString;
import com.google.recaptchaenterprise.v1.AccountDefenderAssessment.AccountDefenderLabel;
import com.google.recaptchaenterprise.v1.Assessment;
import com.google.recaptchaenterprise.v1.CreateAssessmentRequest;
import com.google.recaptchaenterprise.v1.Event;
import com.google.recaptchaenterprise.v1.ProjectName;
import com.google.recaptchaenterprise.v1.RiskAnalysis.ClassificationReason;
import com.google.recaptchaenterprise.v1.TokenProperties;
import com.google.recaptchaenterprise.v1.UserId;
import com.google.recaptchaenterprise.v1.UserInfo;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.UUID;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class AccountDefenderAssessment {

  public static void main(String[] args)
      throws IOException, NoSuchAlgorithmException, InvalidKeyException {
    // TODO(developer): Replace these variables before running the sample.
    // projectId: Google Cloud Project ID
    String projectId = "project-id";

    // recaptchaSiteKey: Site key obtained by registering a domain/app to use recaptcha
    // services.
    String recaptchaSiteKey = "recaptcha-site-key";

    // token: The token obtained from the client on passing the recaptchaSiteKey.
    // To get the token, integrate the recaptchaSiteKey with frontend. See,
    // https://cloud.google.com/recaptcha-enterprise/docs/instrument-web-pages#frontend_integration_score
    String token = "recaptcha-token";

    // recaptchaAction: The action name corresponding to the token.
    String recaptchaAction = "recaptcha-action";

    // Unique ID of the user, such as email, customer ID, etc.
    String accountId = "default" + UUID.randomUUID().toString().split("-")[0];

    // User phone number
    String phoneNumber = "555-987-XXXX";

    // User email address
    String emailAddress = "john.doe@example.com";

    accountDefenderAssessment(projectId, recaptchaSiteKey, token, recaptchaAction, accountId, phoneNumber, emailAddress);
  }

  /**
   * This assessment detects account takeovers. See,
   * https://cloud.google.com/recaptcha-enterprise/docs/account-takeovers The input is the hashed
   * account id. Result tells if the action represents an account takeover. You can optionally
   * trigger a Multi-Factor Authentication based on the result.
   */
  public static void accountDefenderAssessment(
      String projectId,
      String recaptchaSiteKey,
      String token,
      String recaptchaAction,
      String accountId,
      String phoneNumber,
      String emailAddress)
      throws IOException {
    try (RecaptchaEnterpriseServiceClient client = RecaptchaEnterpriseServiceClient.create()) {

      // Set the properties of the event to be tracked.
      Event.Builder eventBuilder =
          Event.newBuilder()
              .setSiteKey(recaptchaSiteKey)
              .setToken(token);

      // Set the account id, email address and phone number (of the user).
      eventBuilder.setUserInfo(
        UserInfo.newBuilder()
          .setAccountId(accountId)
          .addUserIds(UserId.newBuilder().setEmail(emailAddress))
          .addUserIds(UserId.newBuilder().setPhoneNumber(phoneNumber)));

      Event event = eventBuilder.build();

      // Build the assessment request.
      CreateAssessmentRequest createAssessmentRequest =
          CreateAssessmentRequest.newBuilder()
              .setParent(ProjectName.of(projectId).toString())
              .setAssessment(Assessment.newBuilder().setEvent(event).build())
              .build();

      Assessment response = client.createAssessment(createAssessmentRequest);

      // Check integrity of the response token.
      if (!checkTokenIntegrity(response.getTokenProperties(), recaptchaAction)) {
        return;
      }

      // Get the reason(s) and the reCAPTCHA risk score.
      // For more information on interpreting the assessment,
      // see: https://cloud.google.com/recaptcha-enterprise/docs/interpret-assessment
      for (ClassificationReason reason : response.getRiskAnalysis().getReasonsList()) {
        System.out.println(reason);
      }
      float recaptchaScore = response.getRiskAnalysis().getScore();
      System.out.println("The reCAPTCHA score is: " + recaptchaScore);
      String assessmentName = response.getName();
      System.out.println(
          "Assessment name: " + assessmentName.substring(assessmentName.lastIndexOf("/") + 1));

      // Get the Account Defender result.
      com.google.recaptchaenterprise.v1.AccountDefenderAssessment accountDefenderAssessment =
          response.getAccountDefenderAssessment();
      System.out.println(accountDefenderAssessment);

      // Get Account Defender label.
      List<AccountDefenderLabel> defenderResult =
          response.getAccountDefenderAssessment().getLabelsList();
      // Based on the result, can you choose next steps.
      // If the 'defenderResult' field is empty, it indicates that Account Defender did not have
      // anything to add to the score.
      // Few result labels: ACCOUNT_DEFENDER_LABEL_UNSPECIFIED, PROFILE_MATCH,
      // SUSPICIOUS_LOGIN_ACTIVITY, SUSPICIOUS_ACCOUNT_CREATION, RELATED_ACCOUNTS_NUMBER_HIGH.
      // For more information on interpreting the assessment, see:
      // https://cloud.google.com/recaptcha-enterprise/docs/account-defender#interpret-assessment-details
      System.out.println("Account Defender Assessment Result: " + defenderResult);
    }
  }

  private static boolean checkTokenIntegrity(
      TokenProperties tokenProperties, String recaptchaAction) {
    // Check if the token is valid.
    if (!tokenProperties.getValid()) {
      System.out.println(
          "The Account Defender Assessment call failed because the token was: "
              + tokenProperties.getInvalidReason().name());
      return false;
    }

    // Check if the expected action was executed.
    if (!tokenProperties.getAction().equals(recaptchaAction)) {
      System.out.printf(
          "The action attribute in the reCAPTCHA tag '%s' does not match "
              + "the action '%s' you are expecting to score",
          tokenProperties.getAction(), recaptchaAction);
      return false;
    }
    return true;
  }
}

解读关键用户事件的风险判定结果

在启用账号卫士的情况下创建评估时,账号卫士会在评估响应中返回 accountDefenderAssessmentaccountDefenderAssessment 的值可帮助您评估用户活动是合法的,还是欺诈活动。它还会返回您在为用户事件添加注释时需要使用的评估 ID。

以下示例是 JSON 响应示例:

{
  "tokenProperties": {
    "valid": true,
    "androidPackageName": "com.example.app" or "iosBundleId": "com.example.app",
    "action": "login",
    "createTime": "2019-03-28T12:24:17.894Z"
   },
  "riskAnalysis": {
    "score": 0.6,
  },
 "event": {
    "token": "TOKEN",
    "siteKey": "KEY_ID",
    "expectedAction": "USER_ACTION"
  },
  "name": "projects/PROJECT_ID/assessments/b6ac310000000000X",
  "accountDefenderAssessment": {
    labels: ["SUSPICIOUS_LOGIN_ACTIVITY"]
  }
}

accountDefenderAssessment 字段可以具有以下任意值:

说明
SUSPICIOUS_LOGIN_ACTIVITY 表示相应请求存在高凭据填充或账号盗用风险。
SUSPICIOUS_ACCOUNT_CREATION 表示相应请求存在高滥用账号创建风险。
PROFILE_MATCH

表示用户的属性与之前看到的此特定用户的属性匹配。此值表示此用户使用的是之前用于访问您的移动应用的可信设备。

只有在以下情况下,系统才会返回 PROFILE_MATCH

  • 您可以使用多重身份验证(MFA) 或双重身份验证(2FA),reCAPTCHA 账号卫士会在用户通过 MFA 或 2FA 挑战后将用户个人资料标记为可信。
  • 您将评估注解为 LEGITIMATEPASSED_TWO_FACTOR,并且 reCAPTCHA 账号卫士会将相应的用户个人资料标记为可信。

为事件添加注释,以调整特定于您网站的模型

若要向 reCAPTCHA 账号卫士提供更多信息并改进网站专属检测模型,您必须通过创建评估来为已评估的事件添加注释。

如需为评估添加注释,请向 projects.assessments.annotate 方法发送包含评估 ID 的请求。在该请求的正文中,您可以添加标签,以提供有关评估中所述事件的更多信息。

如需为评估添加注解,请执行以下操作:

  1. 根据您的使用场景确定要在请求 JSON 正文中添加的信息和标签。

    下表列出了可用于为事件添加注解的标签和值:

    标签 说明 请求示例
    reasons 必需。用于支持您的评估的标签。

    请在事件发生后的几秒或几分钟内在 reasons 标签中提供实时事件详情,因为这些详情会影响实时检测。

    如需查看可能值的列表,请参阅原因值

    示例:如需检测账号盗用,请使用 CORRECT_PASSWORDINCORRECT_PASSWORD 值注解输入的密码是否正确。如果您部署了自己的多重身份验证 (MFA),则可以添加以下值:INITIATED_TWO_FACTORPASSED_TWO_FACTORFAILED_TWO_FACTOR

          {
          "reasons": ["INCORRECT_PASSWORD"]
          }
        
    annotation 可选。用于指示评估结果是否合法的标签。

    提供有关登录和注册事件的事实,以验证或更正 annotation 标签中的风险评估。

    可能的值:LEGITIMATEFRAUDULENT

    您可以随时发送此类信息,也可以在批量作业中发送。 不过,我们建议您在事件发生几秒或几分钟后发送此类信息,因为这些信息会影响实时检测。

          {
           "annotation": "LEGITIMATE"
          }
    
      
    accountId

    可选。用于将账号 ID 与事件相关联的标签。

    如果您创建的评估没有账号 ID,请使用此标签在有可用账号 ID 时提供事件的账号 ID。

      {
       "accountId": "ACCOUNT_ID"
      }
  2. 使用适当的标签创建注解请求。

    在使用任何请求数据之前,请先进行以下替换:

    • ASSESSMENT_ID:从 projects.assessments.create 调用返回的 name 字段的值。
    • ANNOTATION:可选。指示评估结果是合法还是欺诈的标签。
    • REASONS:可选。佐证您添加注解的原因。如需查看可能值的列表,请参阅原因值
    • ACCOUNT_ID:可选。与您应用中的用户账号唯一关联的标识符。

    如需了解详情,请参阅注解标签

    HTTP 方法和网址:

    POST https://recaptchaenterprise.googleapis.com/v1/ASSESSMENT_ID:annotate

    请求 JSON 正文:

    {
      "annotation": ANNOTATION,
      "reasons": REASONS,
      "accountId": ACCOUNT_ID
    }
    

    如需发送请求,请选择以下方式之一:

    curl

    将请求正文保存在名为 request.json 的文件中,然后执行以下命令:

    curl -X POST \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    -H "Content-Type: application/json; charset=utf-8" \
    -d @request.json \
    "https://recaptchaenterprise.googleapis.com/v1/ASSESSMENT_ID:annotate"

    PowerShell

    将请求正文保存在名为 request.json 的文件中,然后执行以下命令:

    $cred = gcloud auth print-access-token
    $headers = @{ "Authorization" = "Bearer $cred" }

    Invoke-WebRequest `
    -Method POST `
    -Headers $headers `
    -ContentType: "application/json; charset=utf-8" `
    -InFile request.json `
    -Uri "https://recaptchaenterprise.googleapis.com/v1/ASSESSMENT_ID:annotate" | Select-Object -Expand Content

    您应该会收到一个成功的状态代码 (2xx) 和一个空响应。

代码示例

Java

如需向 reCAPTCHA 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅为本地开发环境设置身份验证


import com.google.cloud.recaptchaenterprise.v1.RecaptchaEnterpriseServiceClient;
import com.google.protobuf.ByteString;
import com.google.recaptchaenterprise.v1.AnnotateAssessmentRequest;
import com.google.recaptchaenterprise.v1.AnnotateAssessmentRequest.Annotation;
import com.google.recaptchaenterprise.v1.AnnotateAssessmentRequest.Reason;
import com.google.recaptchaenterprise.v1.AnnotateAssessmentResponse;
import com.google.recaptchaenterprise.v1.AssessmentName;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;

public class AnnotateAccountDefenderAssessment {

  public static void main(String[] args) throws IOException, NoSuchAlgorithmException {
    // TODO(developer): Replace these variables before running the sample.
    // projectID: GCloud Project id.
    String projectID = "project-id";

    // assessmentId: Value of the 'name' field returned from the CreateAssessment call.
    String assessmentId = "account-defender-assessment-id";

    // accountId: Set the accountId corresponding to the assessment id.
    String accountId = "default" + UUID.randomUUID().toString().split("-")[0];

    annotateAssessment(projectID, assessmentId, accountId);
  }

  /**
   * Pre-requisite: Create an assessment before annotating. Annotate an assessment to provide
   * feedback on the correctness of recaptcha prediction.
   */
  public static void annotateAssessment(
      String projectID, String assessmentId, String accountId) throws IOException {

    try (RecaptchaEnterpriseServiceClient client = RecaptchaEnterpriseServiceClient.create()) {
      // Build the annotation request.
      // For more info on when/how to annotate, see:
      // https://cloud.google.com/recaptcha-enterprise/docs/annotate-assessment#when_to_annotate
      AnnotateAssessmentRequest annotateAssessmentRequest =
          AnnotateAssessmentRequest.newBuilder()
              .setName(AssessmentName.of(projectID, assessmentId).toString())
              .setAnnotation(Annotation.LEGITIMATE)
              .addReasons(Reason.PASSED_TWO_FACTOR)
              .setAccountId(accountId)
              .build();

      // Empty response is sent back.
      AnnotateAssessmentResponse response = client.annotateAssessment(annotateAssessmentRequest);
      System.out.println("Annotated response sent successfully ! " + response);
    }
  }
}

启用 reCAPTCHA 账号卫士

为移动应用配置 reCAPTCHA 账号卫士后,您就可以启用 reCAPTCHA 账号卫士了。

  1. 在 Google Cloud 控制台中,前往 reCAPTCHA 页面。

    前往 reCAPTCHA

  2. 验证项目名称是否显示在页面顶部的资源选择器中。

    如果您没有看到项目名称,请点击资源选择器,然后选择您的项目。

  3. 点击 设置
  4. 账号卫士窗格中,点击配置

  5. 配置账号卫士对话框中,点击启用,然后点击保存

启用 reCAPTCHA 账号卫士的操作可能需要几个小时才能传播到我们的系统。启用该功能的操作传播到我们的系统后,您将在评估过程中开始接收与账号卫士相关的响应。

后续步骤