Detecta filtraciones de contraseñas y credenciales vulneradas

En esta página, se describe cómo usar la función de detección de filtración de contraseñas de reCAPTCHA Enterprise para detectar filtraciones de contraseñas y credenciales vulneradas con el objetivo de evitar la apropiación de cuentas (ATO) y los ataques de uso excesivo de credenciales. Con reCAPTCHA Enterprise, puedes realizar auditorías regulares de las credenciales de los usuarios (contraseñas) como parte de cualquier evaluación para asegurarte de que no se hayan filtrado ni vulnerado. Para realizar estas evaluaciones, Google usa la función de Revisión de contraseñas.

Antes de comenzar

  1. Prepara tu entorno para reCAPTCHA Enterprise.

  2. Configura reCAPTCHA Enterprise.

  3. Asegúrate de que la facturación esté habilitada para tu proyecto de Google Cloud.

    reCAPTCHA Enterprise requiere que la facturación esté vinculada y habilitada en el proyecto para usar la función de detección de filtración de contraseñas. Puedes habilitar la facturación con una tarjeta de crédito o un ID de facturación de un proyecto de Google Cloud existente. Si necesitas ayuda con la facturación, comunícate con el equipo de asistencia de Facturación de Cloud.

Verifica si hay credenciales filtradas y filtradas

Para comprobar si se vulneró un conjunto de credenciales, usa la detección de filtración de contraseñas cuando crees evaluaciones de acciones como accesos, cambios de contraseñas y restablecimientos de contraseñas.

Para comprobar si hay filtraciones de contraseñas y credenciales violadas, completa los siguientes pasos:

  1. Genera parámetros de solicitud.
  2. Crea una evaluación para detectar filtraciones de contraseñas.
  3. Verifica las credenciales filtradas en una evaluación.
  4. Interpreta el veredicto y toma medidas.

Genera parámetros de solicitud

  1. Calcula los parámetros de solicitud necesarios con las funciones criptográficas que requiere el protocolo de alta privacidad. reCAPTCHA Enterprise proporciona bibliotecas de Java y TypeScript para ayudar a generar estos campos:

  2. Para generar verificaciones de verificación de contraseñas, crea un objeto PasswordCheckVerifier.

    PasswordCheckVerifier verifier = new PasswordCheckVerifier();
    
  3. Para iniciar una verificación, llama a PasswordCheckVerifier#createVerification. Este método usa el nombre de usuario y la contraseña para calcular los parámetros a fin de realizar la verificación de la contraseña.

    PasswordCheckVerification verification = verifier.createVerification("username", "password").get();
    
  4. Crea una evaluación con los parámetros de verificación.

    byte[] lookupHashPrefix = verification.getLookupHashPrefix();
    byte[] encryptedUserCredentialsHash = verification.getEncryptedUserCredentialsHash();
    

    Los arrays de bytes lookupHashPrefix y encryptedUserCredentialsHash contienen los parámetros necesarios para iniciar una verificación de contraseña Assessment.

Crear una evaluación para detectar filtraciones de contraseñas

Usa el método projects.assessments.create.

Antes de usar cualquiera de los datos de solicitud a continuación, realiza los siguientes reemplazos:

  • PROJECT_ID: El ID del proyecto de Google Cloud.
  • LOOKUP_HASH_PREFIX: Prefijo del nombre de usuario SHA-256 del prefijo de hash
  • ENCRYPTED_USER_CREDENTIALS_HASH: Hash de Scrypt de credenciales de usuario encriptadas

HTTP method and URL:

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

Cuerpo JSON de la solicitud:

{
  "private_password_leak_verification": {
    "lookup_hash_prefix": "LOOKUP_HASH_PREFIX",
    "encrypted_user_credentials_hash": "ENCRYPTED_USER_CREDENTIALS_HASH"
  }
}

Para enviar tu solicitud, elige una de estas opciones:

curl

Guarda el cuerpo de la solicitud en un archivo llamado request.json y ejecuta el siguiente comando:

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

Guarda el cuerpo de la solicitud en un archivo llamado request.json y ejecuta el siguiente comando:

$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

Deberías recibir una respuesta JSON similar a la que se muestra a continuación:

{
  "name": "projects/698047609967/assessments/fb22000000000000",
  "score": 0,
  "reasons": [],
  "privatePasswordLeakVerification": {
    "lookupHashPrefix": "zoxZwA==",
    "encryptedUserCredentialsHash": "AyRihRcKaGLj/FA/r2uqQY/fzfTaDb/nEcIUMeD3Tygp",
    "reencryptedUserCredentialsHash": "Aw65yEbLM39ww1ridDEfx5VhkWo11tzn/R1B88Qqwr/+"
    "encryptedLeakMatchPrefixes": [
      "n/n5fvPD6rmQPFyb4xk=", "IVQqzXsbZenaibID6OI=", ..., "INeMMndrfnlf6osCVvs=",
      "MkIpxt2x4mtyBnRODu0=", "AqUyAUWzi+v7Kx03e6o="]
  }
}

Verificar las credenciales filtradas desde una evaluación

De la respuesta de la evaluación, extrae los campos reEncryptedUserCredentials y encryptedLeakMatchPrefixes, y pásalos al objeto verificador para determinar si las credenciales se filtraron o no.

PasswordCheckResult result = verifier.verify(verification,
  result.getReEncryptedUserCredentials(),
  result.getEncryptedLeakMatchPrefixes()
).get();

System.out.println("Credentials leaked: " + result.areCredentialsLeaked());

Interpreta el veredicto y toma medidas

La respuesta de la evaluación muestra si se filtraron las credenciales y te proporciona información que puedes usar para tomar las medidas adecuadas y proteger a tus usuarios.

En la siguiente tabla, se enumeran las acciones recomendadas que puedes realizar cuando se detecta una contraseña filtrada:

Se detectó una contraseña filtrada Acciones para proteger al usuario
Durante el acceso
  • Rechazar y requerir que el cliente elija una contraseña diferente y, si es posible, activar un desafío de MFA.
  • Recuérdale al usuario que use contraseñas únicas en todas las cuentas.
  • Solicitar contraseñas seguras en tu sitio
  • Pídele al usuario que habilite la autenticación de varios factores (MFA) si no la está usando.
Durante la creación de la cuenta o el restablecimiento de la contraseña
  • Pídele al usuario que cambie la contraseña.
  • Activa un flujo de autenticación de varios factores (MFA).

Si todavía no utilizas un proveedor de MFA en tu sitio, puedes usar la función de MFA de reCAPTCHA Enterprise.

Muestra de código

Java

Para autenticarte en reCAPTCHA Enterprise, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.


import com.google.cloud.recaptcha.passwordcheck.PasswordCheckResult;
import com.google.cloud.recaptcha.passwordcheck.PasswordCheckVerification;
import com.google.cloud.recaptcha.passwordcheck.PasswordCheckVerifier;
import com.google.cloud.recaptchaenterprise.v1.RecaptchaEnterpriseServiceClient;
import com.google.protobuf.ByteString;
import com.google.recaptchaenterprise.v1.Assessment;
import com.google.recaptchaenterprise.v1.CreateAssessmentRequest;
import com.google.recaptchaenterprise.v1.PrivatePasswordLeakVerification;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import org.bouncycastle.util.encoders.Base64;

public class CreatePasswordLeakAssessment {

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

    // Username and password to be checked for credential breach.
    String username = "username";
    String password = "password";

    checkPasswordLeak(projectID, username, password);
  }

  /*
   * Detect password leaks and breached credentials to prevent account takeovers
   * (ATOs) and credential stuffing attacks.
   * For more information, see:
   * https://cloud.google.com/recaptcha-enterprise/docs/check-passwords and
   * https://security.googleblog.com/2019/02/protect-your-accounts-from-data.html

   * Steps:
   * 1. Use the 'create' method to hash and Encrypt the hashed username and
   * password.
   * 2. Send the hash prefix (26-bit) and the encrypted credentials to create
   * the assessment.(Hash prefix is used to partition the database.)
   * 3. Password leak assessment returns a list of encrypted credential hashes to
   * be compared with the decryption of the returned re-encrypted credentials.
   * Create Assessment also sends back re-encrypted credentials.
   * 4. The re-encrypted credential is then locally verified to see if there is
   * a match in the database.
   *
   * To perform hashing, encryption and verification (steps 1, 2 and 4),
   * reCAPTCHA Enterprise provides a helper library in Java.
   * See, https://github.com/GoogleCloudPlatform/java-recaptcha-password-check-helpers

   * If you want to extend this behavior to your own implementation/ languages,
   * make sure to perform the following steps:
   * 1. Hash the credentials (First 26 bits of the result is the
   * 'lookupHashPrefix')
   * 2. Encrypt the hash (result = 'encryptedUserCredentialsHash')
   * 3. Get back the PasswordLeak information from
   * reCAPTCHA Enterprise Create Assessment.
   * 4. Decrypt the obtained 'credentials.getReencryptedUserCredentialsHash()'
   * with the same key you used for encryption.
   * 5. Check if the decrypted credentials are present in
   * 'credentials.getEncryptedLeakMatchPrefixesList()'.
   * 6. If there is a match, that indicates a credential breach.
   */
  public static void checkPasswordLeak(
      String projectID, String username, String password)
      throws ExecutionException, InterruptedException, IOException {

    // Instantiate the java-password-leak-helper library to perform the cryptographic functions.
    PasswordCheckVerifier passwordLeak = new PasswordCheckVerifier();

    // Create the request to obtain the hash prefix and encrypted credentials.
    PasswordCheckVerification verification =
        passwordLeak.createVerification(username, password).get();

    byte[] lookupHashPrefix = Base64.encode(verification.getLookupHashPrefix());
    byte[] encryptedUserCredentialsHash = Base64.encode(
        verification.getEncryptedUserCredentialsHash());

    // Pass the credentials to the createPasswordLeakAssessment() to get back
    // the matching database entry for the hash prefix.
    PrivatePasswordLeakVerification credentials =
        createPasswordLeakAssessment(
            projectID,
            lookupHashPrefix,
            encryptedUserCredentialsHash);

    // Convert to appropriate input format.
    List<byte[]> leakMatchPrefixes =
        credentials.getEncryptedLeakMatchPrefixesList().stream()
            .map(x -> Base64.decode(x.toByteArray()))
            .collect(Collectors.toList());

    // Verify if the encrypted credentials are present in the obtained match list.
    PasswordCheckResult result =
        passwordLeak
            .verify(
                verification,
                Base64.decode(credentials.getReencryptedUserCredentialsHash().toByteArray()),
                leakMatchPrefixes)
            .get();

    // Check if the credential is leaked.
    boolean isLeaked = result.areCredentialsLeaked();
    System.out.printf("Is Credential leaked: %s", isLeaked);
  }

  // Create a reCAPTCHA Enterprise assessment.
  // Returns:  PrivatePasswordLeakVerification which contains
  // reencryptedUserCredentialsHash and credential breach database
  // whose prefix matches the lookupHashPrefix.
  private static PrivatePasswordLeakVerification createPasswordLeakAssessment(
      String projectID,
      byte[] lookupHashPrefix,
      byte[] encryptedUserCredentialsHash)
      throws IOException {
    try (RecaptchaEnterpriseServiceClient client = RecaptchaEnterpriseServiceClient.create()) {

      // Set the hashprefix and credentials hash.
      // Setting this will trigger the Password leak protection.
      PrivatePasswordLeakVerification passwordLeakVerification =
          PrivatePasswordLeakVerification.newBuilder()
              .setLookupHashPrefix(ByteString.copyFrom(lookupHashPrefix))
              .setEncryptedUserCredentialsHash(ByteString.copyFrom(encryptedUserCredentialsHash))
              .build();

      // Build the assessment request.
      CreateAssessmentRequest createAssessmentRequest =
          CreateAssessmentRequest.newBuilder()
              .setParent(String.format("projects/%s", projectID))
              .setAssessment(
                  Assessment.newBuilder()
                      // Set request for Password leak verification.
                      .setPrivatePasswordLeakVerification(passwordLeakVerification)
                      .build())
              .build();

      // Send the create assessment request.
      Assessment response = client.createAssessment(createAssessmentRequest);

      // Get the reCAPTCHA Enterprise score.
      float recaptchaScore = response.getRiskAnalysis().getScore();
      System.out.println("The reCAPTCHA score is: " + recaptchaScore);

      // Get the assessment name (id). Use this to annotate the assessment.
      String assessmentName = response.getName();
      System.out.println(
          "Assessment name: " + assessmentName.substring(assessmentName.lastIndexOf("/") + 1));

      return response.getPrivatePasswordLeakVerification();
    }
  }
}

Node.js (TypeScript)

Para autenticarte en reCAPTCHA Enterprise, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.


import {google} from '@google-cloud/recaptcha-enterprise/build/protos/protos';
import {RecaptchaEnterpriseServiceClient} from '@google-cloud/recaptcha-enterprise';
import {PasswordCheckVerification} from 'recaptcha-password-check-helpers';

// TODO(developer): Uncomment and set the following variables
// Google Cloud Project ID.
// const projectId: string = "PROJECT_ID"

// Username and password to be checked for credential breach.
// const username: string = "user123";
// const password: string = "1234@abcd";

// Create a client.
const client: RecaptchaEnterpriseServiceClient =
  new RecaptchaEnterpriseServiceClient();

/*
* Detect password leaks and breached credentials to prevent account takeovers
* (ATOs) and credential stuffing attacks.
* For more information, see:
* https://cloud.google.com/recaptcha-enterprise/docs/check-passwords and
* https://security.googleblog.com/2019/02/protect-your-accounts-from-data.html

* Steps:
* 1. Use the 'create' method to hash and Encrypt the hashed username and
* password.
* 2. Send the hash prefix (26-bit) and the encrypted credentials to create
* the assessment.(Hash prefix is used to partition the database.)
* 3. Password leak assessment returns a list of encrypted credential hashes to
* be compared with the decryption of the returned re-encrypted credentials.
* Create Assessment also sends back re-encrypted credentials.
* 4. The re-encrypted credential is then locally verified to see if there is
* a match in the database.
*
* To perform hashing, encryption and verification (steps 1, 2 and 4),
* reCAPTCHA Enterprise provides a helper library in Typescript.
* See, https://github.com/GoogleCloudPlatform/typescript-recaptcha-password-check-helpers

* If you want to extend this behavior to your own implementation/ languages,
* make sure to perform the following steps:
* 1. Hash the credentials (First 26 bits of the result is the
* 'lookupHashPrefix')
* 2. Encrypt the hash (result = 'encryptedUserCredentialsHash')
* 3. Get back the PasswordLeak information from
* reCAPTCHA Enterprise Create Assessment.
* 4. Decrypt the obtained 'credentials.getReencryptedUserCredentialsHash()'
* with the same key you used for encryption.
* 5. Check if the decrypted credentials are present in
* 'credentials.getEncryptedLeakMatchPrefixesList()'.
* 6. If there is a match, that indicates a credential breach.
*/
async function checkPasswordLeak(
  projectId: string,
  username: string,
  password: string
) {
  // Instantiate the recaptcha-password-check-helpers library to perform the
  // cryptographic functions.
  // Create the request to obtain the hash prefix and encrypted credentials.
  const verification: PasswordCheckVerification =
    await PasswordCheckVerification.create(username, password);

  const lookupHashPrefix: string = Buffer.from(
    verification.getLookupHashPrefix()
  ).toString('base64');
  const encryptedUserCredentialsHash: string = Buffer.from(
    verification.getEncryptedUserCredentialsHash()
  ).toString('base64');
  console.log('Hashes created.');

  // Pass the credentials to the createPasswordLeakAssessment() to get back
  // the matching database entry for the hash prefix.
  const credentials: google.cloud.recaptchaenterprise.v1.IPrivatePasswordLeakVerification =
    await createPasswordLeakAssessment(
      projectId,
      lookupHashPrefix,
      encryptedUserCredentialsHash
    );

  // Convert to appropriate input format.
  const reencryptedUserCredentialsHash: Uint8Array = Buffer.from(
    credentials.reencryptedUserCredentialsHash!.toString(),
    'base64'
  );
  const encryptedLeakMatchPrefixes: Uint8Array[] =
    credentials.encryptedLeakMatchPrefixes!.map(prefix => {
      return Buffer.from(prefix.toString(), 'base64');
    });

  // Verify if the encrypted credentials are present in the obtained
  // match list to check if the credential is leaked.
  const isLeaked: boolean = verification
    .verify(reencryptedUserCredentialsHash, encryptedLeakMatchPrefixes)
    .areCredentialsLeaked();

  console.log(`Is Credential leaked: ${isLeaked}`);
}

// Create a reCAPTCHA Enterprise assessment.
// Returns: PrivatePasswordLeakVerification which contains
// reencryptedUserCredentialsHash and credential breach database whose prefix
// matches the lookupHashPrefix.
async function createPasswordLeakAssessment(
  projectId: string,
  lookupHashPrefix: string,
  encryptedUserCredentialsHash: string
): Promise<google.cloud.recaptchaenterprise.v1.IPrivatePasswordLeakVerification> {
  // Build the assessment request.
  const createAssessmentRequest: google.cloud.recaptchaenterprise.v1.ICreateAssessmentRequest =
    {
      parent: `projects/${projectId}`,
      assessment: {
        // Set the hashprefix and credentials hash.
        // Setting this will trigger the Password leak protection.
        privatePasswordLeakVerification: {
          lookupHashPrefix: lookupHashPrefix,
          encryptedUserCredentialsHash: encryptedUserCredentialsHash,
        },
      },
    };

  // Send the create assessment request.
  const [response] = await client.createAssessment(createAssessmentRequest);

  // Get the reCAPTCHA Enterprise score.
  console.log(`The reCAPTCHA score is: ${response.riskAnalysis?.score}`);
  // Get the assessment name (id). Use this to annotate the assessment.
  console.log(`Assessment name: ${response.name}`);

  if (!response?.privatePasswordLeakVerification) {
    throw `Error in obtaining response from Private Password Leak Verification ${response}`;
  }

  return response.privatePasswordLeakVerification;
}

checkPasswordLeak(projectId, username, password).catch(err => {
  console.error(err.message);
  process.exitCode = 1;
});

¿Qué sigue?