Detect and prevent SMS fraud

This document shows you how to use reCAPTCHA SMS toll fraud protection to detect and prevent SMS pumping attacks in businesses that rely on SMS for two-factor authentication (2FA) or phone verification, which is a potential target for SMS toll fraud.

SMS-based authentication (2FA and login) is an industry standard for login and signup security, but it doesn't provide protection against SMS toll fraud or SMS pumping fraud. Before you send an SMS, reCAPTCHA SMS toll fraud protection provides you with a risk score that indicates the likelihood of that phone number committing SMS toll fraud. Based on this score, you can allow or block fraudulent SMS messages before they are sent to your SMS provider.

For additional information, see the reCAPTCHA SMS toll fraud protection blog.

Before you begin

Depending on whether you are an existing user of reCAPTCHA or new to reCAPTCHA, follow the instructions in the appropriate tab:

Existing reCAPTCHA user

If you are an existing user of reCAPTCHA, then enable reCAPTCHA SMS toll fraud protection on your Google Cloud project:

  1. In the Google Cloud console, go to the reCAPTCHA page.

    Go to reCAPTCHA

  2. Verify that the name of your project appears in the resource selector.

    If you don't see the name of your project, click the resource selector, and then select your project.

  3. Click Settings.

  4. In the SMS Toll Fraud Protection pane, click Configure.

  5. Click the Enable toggle, and click Save.

    Enabling SMS toll fraud protection enables account defender if it is not yet enabled.

    It might take a few minutes for the reCAPTCHA SMS toll fraud protection enablement to propagate to our systems. After the feature enablement is propagated to our systems, you should start receiving responses related to reCAPTCHA SMS toll fraud protection as part of the assessments.

New reCAPTCHA user

If you are new to reCAPTCHA, do the following:

  1. Depending on whether you want to use reCAPTCHA SMS toll fraud protection on a website or mobile application, follow these steps to integrate reCAPTCHA:

  2. Enable reCAPTCHA SMS toll fraud protection on your Google Cloud project:
    1. In the Google Cloud console, go to the reCAPTCHA page.

      Go to reCAPTCHA

    2. Verify that the name of your project appears in the resource selector.

      If you don't see the name of your project, click the resource selector, and then select your project.

    3. Click Settings.

    4. In the SMS Toll Fraud Protection pane, click Configure.

    5. Click the Enable toggle, and click Save.

      Enabling SMS toll fraud protection enables account defender if it is not yet enabled.

      It might take a few minutes for the reCAPTCHA SMS toll fraud protection enablement to propagate to our systems. After the feature enablement is propagated to our systems, you should start receiving responses related to reCAPTCHA SMS toll fraud protection as part of the assessments.

Create an assessment with the phone number

For reCAPTCHA SMS toll fraud protection, create assessments with the token that is generated by the execute() function and the phone number, by using either the reCAPTCHA Client Libraries or the REST API from your backend.

This document shows how to create an assessment using the REST API. To learn how to create an assessment using Client Libraries, see Create assessments.

Before you create an assessment, do the following:

  • Set up authentication to reCAPTCHA.

    The authentication method you choose depends on the environment where reCAPTCHA is set up. The following table helps you choose the appropriate authentication method and the supported interface to set up authentication:

    Environment Interface Authentication method
    Google Cloud
    • REST
    • Client libraries
    Use attached service accounts.
    On-premises or a different cloud provider REST Use API keys or Workload Identity Federation.

    If you want to use API keys, then we recommend securing the API keys by applying API key restrictions.

    Client libraries

    Use the following:

  • Choose a stable account identifier accountId that is not often changed by the user and provide it to the assessment in the projects.assessments.create method. This stable account identifier should have the same value for all the events related to the same user. You can provide the following as the account identifier:

    User identifiers

    If every account can be uniquely associated with a stable username, email address, or phone number, you can use it as the accountId. When you provide such cross-site identifiers (identifiers that can be reused across sites), reCAPTCHA uses this information to improve protection for your user accounts based on cross-site models by flagging abusive account identifiers and using knowledge of cross-site abuse patterns related to these identifiers.

    Alternatively, if you have an internal user ID uniquely associated with each account, you can provide it as the accountId.

    Hashed or encrypted

    If you do not have an internal user ID uniquely associated with each account, you can turn any stable identifier into an opaque, site-specific account identifier. This identifier is still needed for reCAPTCHA account defender to understand user activity patterns and detect anomalous behaviour, but it is not shared across other sites.

    Pick any stable account identifier and make it opaque before sending to reCAPTCHA by using encryption or hashing:

    • encryption (recommended): encrypt the account identifier using a deterministic encryption method that produces a stable ciphertext. For detailed instructions, see encrypt data deterministically. When you choose symmetric encryption over hashing, you don't need to keep a mapping between your user identifiers and the corresponding opaque user identifiers. Decrypt the opaque identifiers that are returned by reCAPTCHA to turn them into the user identifier.

    • hashing: we recommend hashing the account identifier using the SHA256-HMAC method with a custom salt of your choice. Because hashes are one-way only, you need to keep a mapping between the generated hashes and your user identifiers so that you can map the hashed account identifier that are returned back to the original accounts.

Add the accountId parameter and the phone number in the E.164 format as the UserId to verify in the assessment in the projects.assessments.create method.

Before using any of the request data, make the following replacements:

  • PROJECT_ID: your Google Cloud project ID.
  • TOKEN: token returned from the grecaptcha.enterprise.execute() call.
  • KEY_ID: the score-based key that you installed on your website.
  • ACCOUNT_ID: an identifier for a user account that is unique to your website.
  • PHONE_NUMBER: the phone number that needs to be checked for maliciousness. The phone number must be in the E.164 format and it should not be hashed or encrypted.

HTTP method and URL:

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

Request JSON body:


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

To send your request, choose one of these options:

curl

Save the request body in a file named request.json, and execute the following command:

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

Save the request body in a file named request.json, and execute the following command:

$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

You should receive a JSON response similar to the following:


{
  "event": {
     …
  },
  "name": "ASSESSMENT_ID",
  "phoneFraudAssessment": {
    "smsTollFraudVerdict": {
      "risk": 0.3
    }
  }
}

The response you receive includes the risk score in the phoneFraudAssessment.smsTollFraudVerdict field . The higher the score, the more likely the phone number is risky; the lower the score, the more likely the phone number is legitimate.

You are responsible for the actions that you take based on the assessment. For the simplest integration, you can set thresholds on phoneFraudAssessment.smsTollFraudVerdict.risk to contribute to your decision.

Annotate the assessment

To keep track of the SMS traffic and to improve the fraud detection, you must annotate the assessments within 10 minutes after the SMS is sent or after the phone number is successfully verified.

You annotate an assessment by sending a request to the projects.assessments.annotate method with the assessment ID. In the body of that request, include the phone number in E.164 format in the phoneAuthenticationEvent field.

To annotate an assessment, do the following:

  1. Determine the information and labels to add in the request JSON body depending on your use case.

    The following table lists the labels and values that you can use to annotate events:

    Label Description Request example
    reasons

    Required. A label to support your assessments.

    Provide real-time event details in the reasons label in a few seconds or minutes after the event because they influence real-time detection.

    Possible values:

    • INITIATED_TWO_FACTOR: a verification code through SMS is sent.
    • PASSED_TWO_FACTOR: the verification code is successfully verified.
    • FAILED_TWO_FACTOR: the verification code is invalid.
        {
        "reasons": ["INITIATED_TWO_FACTOR"],
        "phoneAuthenticationEvent": {
          "phoneNumber": "+18005550175"
        }
      }
    annotation

    Optional. A label to indicate the legitimacy of assessments.

    Provide facts about login and registration events to validate or correct your risk assessments in the annotation label.

    Possible values: LEGITIMATE or FRAUDULENT.

    We recommend sending this information in a few seconds or minutes after the event because it influences real-time detection.

      {
       "annotation": "LEGITIMATE"
      }
      
  2. Create an annotate request with the appropriate labels.

    Before using any of the request data, make the following replacements:

    • ASSESSMENT_ID: value of the name field returned from the projects.assessments.create call.
    • ANNOTATION: Optional. A label to indicate whether the assessment is legitimate or fraudulent.
    • REASONS: reasons that support your annotation. For the list of possible values, see reasons values.
    • PHONE_NUMBER: the phone number that was assessed. The phone number must be in the E.164 format and it should not be hashed or encrypted.

    HTTP method and URL:

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

    Request JSON body:

    {
      "annotation": ANNOTATION,
      "reasons": REASONS,
      "phoneAuthenticationEvent": {
        "phoneNumber": "PHONE_NUMBER"
      }
    }
    

    To send your request, choose one of these options:

    curl

    Save the request body in a file named request.json, and execute the following command:

    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

    Save the request body in a file named request.json, and execute the following command:

    $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

    You should receive a successful status code (2xx) and an empty response.

What's next