偵測密碼外洩情形和外洩的憑證

本頁說明如何使用 reCAPTCHA 的密碼防護功能,偵測密碼外洩和遭盜用的憑證,防範帳戶盜用 (ATO) 和憑證填充攻擊。使用 reCAPTCHA 時,您可以定期稽核使用者憑證 (密碼),確保憑證未遭外洩或入侵。Google 會使用「密碼檢查」功能執行這些評估。

事前準備

  1. 準備 reCAPTCHA 環境

  2. 設定 reCAPTCHA

  3. Make sure that billing is enabled for your Google Cloud project.

    如要使用密碼防護功能,專案必須連結並啟用帳單。你可以使用信用卡或現有 Google Cloud 專案帳單 ID 啟用帳單。如需帳單方面的協助,請與 Cloud 帳單支援團隊聯絡。

檢查外洩的憑證

您可以使用加密函式或 Docker 容器,檢查一組憑證是否遭盜用。

Docker 容器是開放原始碼用戶端,可實作安全的多方運算,確保使用者隱私權,並安全地查詢密碼外洩情形。詳情請參閱 GitHub 存放區。 Docker 容器會抽象化實作加密演算法的複雜度,並簡化安裝程序。您也可以在基礎架構中代管容器應用程式。

密碼編譯函式

如要檢查一組憑證是否遭盜用,請在建立登入、變更密碼和重設密碼等動作的評估時,使用密碼防護功能。

如要檢查密碼外洩情況和外洩的憑證,請完成下列步驟:

  1. 生成要求參數
  2. 建立評估作業以偵測密碼外洩情形
  3. 透過評估作業驗證外洩的憑證
  4. 解讀判定結果並採取行動

生成要求參數

  1. 使用高隱私權通訊協定所需的加密函式,計算必要的要求參數。reCAPTCHA 提供 Java 和 TypeScript 程式庫,協助產生這些欄位:

  2. 如要建立密碼檢查驗證,請建立 PasswordCheckVerifier 物件。

    PasswordCheckVerifier verifier = new PasswordCheckVerifier();
    
  3. 如要啟動驗證,請呼叫 PasswordCheckVerifier#createVerification。這個方法會使用使用者名稱和密碼計算參數,以執行密碼檢查。

    PasswordCheckVerification verification = verifier.createVerification("username", "password").get();
    
  4. 使用驗證參數建立評估

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

    位元組陣列 lookupHashPrefixencryptedUserCredentialsHash 包含啟動密碼檢查 Assessment 所需的參數。

建立評估作業以偵測密碼外洩情形

請使用 projects.assessments.create 方法。

使用任何要求資料之前,請先替換以下項目:

  • PROJECT_ID:您的 Google Cloud 專案 ID
  • LOOKUP_HASH_PREFIX:使用者名稱 SHA-256 雜湊前置字串的前置字串
  • ENCRYPTED_USER_CREDENTIALS_HASH:加密使用者憑證 Scrypt 雜湊

HTTP 方法和網址:

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

JSON 要求主體:

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

如要傳送要求,請選擇以下其中一個選項:

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 回應:

{
  "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="]
  }
}

透過評估作業驗證外洩的憑證

從評估回應中擷取 reEncryptedUserCredentialsencryptedLeakMatchPrefixes 欄位,並傳遞至驗證器物件,判斷憑證是否外洩。

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

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

程式碼範例

Node.js (TypeScript)

如要瞭解如何使用 Node.js (TypeScript) 實作密碼外洩偵測功能,請參閱 GitHub 上的 TypeScript 程式碼範例

Java

如要驗證 reCAPTCHA,請設定應用程式預設憑證。 詳情請參閱「為本機開發環境設定驗證」。


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();
    }
  }
}

Docker 容器

如要檢查憑證是否外洩,請使用 localhost 連線或在容器上設定 HTTPS,將使用者名稱和密碼憑證組安全地傳送至容器。然後,容器會加密這些憑證,再向 reCAPTCHA 發出 API 要求,並在本機驗證重新加密的結果。

如要將要求傳送至 Docker 容器,請完成下列步驟:

  1. 設定 Docker
  2. 準備 Docker 容器環境
  3. 建構並執行容器
  4. 向容器傳送 HTTP 要求
  5. 解讀判定結果並採取行動

準備執行 Docker 容器

  1. 選擇驗證策略。

    這個容器支援設定應用程式預設憑證,或接受 API 金鑰進行驗證。

  2. 設定 PLD 容器,以 HTTPS 執行或僅在 localhost 示範模式中執行。

    由於容器會接受敏感的使用者憑證 (使用者名稱和密碼),因此必須透過 HTTPS 執行,或以僅限本機主機的示範模式執行。如需 HTTPS 設定指南,請參閱 GitHub 上的 README

下列步驟會使用 API 金鑰驗證,並在僅限 localhost 的示範模式下執行用戶端。

建構並執行 Docker 容器

  1. 複製存放區:

    git clone github.com/GoogleCloudPlatform/reCAPTCHA-PLD
    
  2. 建構容器:

    docker build . -t pld-local
    
  3. 啟動容器:

    docker run --network host \
    -e RECAPTCHA_PROJECT_ID=PROJECT_ID \
    -e GOOGLE_CLOUD_API_KEY=API_KEY \
    pld-local
    

容器會啟動,並開始在 localhost 的通訊埠 8080 上處理要求。

傳送本機主機要求

使用任何要求資料之前,請先替換以下項目:

  • LEAKED_USERNAME:外洩憑證組合的使用者名稱。
  • LEAKED_PASSWORD:外洩憑證組合的密碼。

HTTP 方法和網址:

POST http://localhost:8080/createAssessment/

JSON 要求主體:

{
    "username":"LEAKED_USERNAME",
    "password":"LEAKED_PASSWORD"
}

如要傳送要求,請選擇以下其中一個選項:

curl

將要求主體儲存在名為 request.json 的檔案中,然後執行下列指令:

curl -X POST \
-H "Content-Type: application/json; charset=utf-8" \
-d @request.json \
"http://localhost:8080/createAssessment/"

PowerShell

將要求主體儲存在名為 request.json 的檔案中,然後執行下列指令:

$headers = @{  }

Invoke-WebRequest `
-Method POST `
-Headers $headers `
-ContentType: "application/json; charset=utf-8" `
-InFile request.json `
-Uri "http://localhost:8080/createAssessment/" | Select-Object -Expand Content

您應該會收到如下的 JSON 回應:


  { "leakedStatus":"LEAKED" }


 OR


  { "leakedStatus":"NO_STATUS" }

解讀判定結果並採取行動

評估結果會顯示憑證是否外洩,並提供相關資訊,協助您採取適當行動來保護使用者。

下表列出系統偵測到外洩密碼時,建議您採取的動作:

偵測到外洩的密碼 保護使用者的措施
登入期間
  • 拒絕並要求顧客選擇其他密碼,且盡可能觸發多重驗證。
  • 提醒使用者為各個帳戶設定不同密碼。
  • 要求網站使用者設定高強度密碼。
  • 如果使用者未啟用多重驗證 (MFA),請提示他們啟用。
建立帳戶或重設密碼時
  • 要求使用者變更密碼。
  • 觸發多重驗證 (MFA) 流程。

如果您的網站尚未採用 MFA 供應商,可以使用 reCAPTCHA 的 MFA 功能

後續步驟