Detecting and preventing account takeovers

This page describes how to detect and prevent account takeovers (ATOs) using reCAPTCHA Enterprise.

ATO attacks typically occur when an attacker sends requests to log in to API endpoints using credentials obtained from a data breach, also known as a password dump. This type of attack can be successful, even if the password dump is from an unrelated site, because humans tend to reuse passwords across multiple accounts. This type of attack does not affect users who practice proper password hygiene, such as using a password manager.

With reCAPTCHA Enterprise, you can detect and prevent ATOs by using one of the following options:

Using the I'm not a robot checkbox

Adding the I'm not a robot checkbox to your site is the fastest and easiest way to provide some protection against ATOs without having to integrate additional features, such as SMS or email verification. There is a cost for an attacker to break this protection and this option might be sufficient for some sites.

Add the "I'm not a robot" checkbox on your web pages.

The following is a live example of a simple login page protected by the checkbox.

function onSuccess(token) {
  // The token is included in the POST data in the g-recaptcha-response
  // parameter. The backend must create an Assessment with the token
  // and verify the token is valid.
  console.log(token);
}
<form id="loginForm" action="?" method="POST">
  Username: <input type="text" name="username"/><br/>
  Password: <input type="password" name="password"/><br/>
  <div class="g-recaptcha" data-sitekey="reCATCHA_sitekey"
       data-action="account_login" data-callback="onSuccess"></div>
</form>
<script src="https://www.google.com/recaptcha/enterprise.js" async defer></script>

You can experiment with this code in JSFiddle by clicking the <> icon in the top-right corner of the code window.

<html>
  <head>
    <title>Account Login - Checkbox</title>
    <script src="https://www.google.com/recaptcha/enterprise.js" async defer></script>
    <script>
    function onSuccess(token) {
      // The token is included in the POST data in the g-recaptcha-response
      // parameter. The backend must create an Assessment with the token
      // and verify the token is valid.
      console.log(token);
    }
    </script>
  </head>
  <body>
    <form id="loginForm" action="?" method="POST">
      Username: <input type="text" name="username"/><br/>
      Password: <input type="password" name="password"/><br/>
      <div class="g-recaptcha" data-sitekey="6LeAkOgUAAAAACcy3uY6N9H9SJMS27n3Zx2OOnYK"
           data-action="account_login" data-callback="onSuccess"></div>
    </form>
  </body>
</html>

Using scores and custom challenges

The best way to protect against ATOs is to rely on the reCAPTCHA score-based site keys and use Multi-factor authentication (MFA) challenges, such as email and SMS challenges in which one-time codes (OTPs) are sent to the user.

Consider the following options to protect against ATOs:

Depending on your use case, you can use MFA on its own or with score-based site keys. For example, you might prefer to use MFA challenges only for scores below a certain threshold to reduce friction.

The following example shows how to integrate score-based site keys in the login scenario.

function submitForm() {
  grecaptcha.enterprise.ready(function() {
    grecaptcha.enterprise.execute(
      'reCAPTCHA_site_key', {action: 'account_login'}).then(function(token) {
       document.getElementById("token").value = token;
       document.getElementByID("loginForm").submit();
    });
  });
}
<form id="loginForm" action="?" method="POST">
  Username: <input type="text" name="username"/><br/>
  Password: <input type="password" name="password"/><br/>
  <input type="hidden" id="token" name="recaptcha_token"/>
  <button onclick="submitForm()">Login</button>
</form>
<script src="https://www.google.com/recaptcha/enterprise.js" async defer></script>

You can experiment with this code in JSFiddle by clicking the <> icon in the top-right corner of the code window.

<html>
  <head>
    <title>Account Login - Score</title>
    <script src="https://www.google.com/recaptcha/enterprise.js" async defer></script>
    <script>
    function submitForm() {
      grecaptcha.enterprise.ready(function() {
        grecaptcha.enterprise.execute(
          'reCAPTCHA_site_key', {action: 'account_login'}).then(function(token) {
           document.getElementById("token").value = token;
           document.getElementByID("loginForm").submit();
        });
      });
    }
    </script>
  </head>
  <body>
    <form id="loginForm" action="?" method="POST">
      Username: <input type="text" name="username"/><br/>
      Password: <input type="password" name="password"/><br/>
      <input type="hidden" id="token" name="recaptcha_token"/>
      <button onclick="submitForm()">Login</button>
    </form>
  </body>
</html>