זיהוי דליפות סיסמאות ופרטי כניסה שנפרצו

בדף הזה מוסבר איך להשתמש בתכונה 'הגנה על סיסמאות' של Fraud Defense כדי לזהות דליפות של סיסמאות ופרטי כניסה שנפרצו, ולמנוע השתלטות על חשבונות (ATO) והתקפות של הכנסת פרטי כניסה (credential stuffing). באמצעות Fraud Defense, אתם יכולים לבצע ביקורות קבועות על פרטי הכניסה (סיסמאות) של המשתמשים כחלק מכל הערכה, כדי לוודא שהם לא נחשפו או נפרצו. כדי לבצע את ההערכות האלה, Google משתמשת בתכונה בדיקת הסיסמאות.

לפני שמתחילים

  1. הכנת הסביבה ל-reCAPTCHA

  2. הגדרת Fraud Defense

  3. מוודאים שהחיוב מופעל בפרויקט Google Cloud .

    כדי להשתמש בתכונה 'הגנה על הסיסמה', Fraud Defense דורש לקשר את החיוב ולהפעיל אותו בפרויקט. אפשר להפעיל את החיוב באמצעות כרטיס אשראי או מזהה חיוב קיים של פרויקט Google Cloud . אם אתם זקוקים לעזרה בנושא חיוב, אתם יכולים לפנות אל צוות התמיכה של חיוב ב-Cloud.

בדיקה של פרטי כניסה שנפרצו או הודלפו

אתם יכולים לבדוק אם קבוצת פרטי כניסה נפרצה באמצעות פונקציות קריפטוגרפיות או באמצעות קובץ Docker.

קונטיינר ה-Docker הוא לקוח בקוד פתוח שמטמיע את החישוב רב-משתתפים המאובטח שנדרש כדי לשמור על פרטיות המשתמשים ולחפש דליפות סיסמאות בצורה מאובטחת. מידע נוסף זמין במאגר GitHub. קונטיינר ה-Docker מפשט את המורכבות של הטמעת האלגוריתמים הקריפטוגרפיים, ומקל על תהליך ההתקנה. הוא גם מאפשר לארח את אפליקציית הקונטיינר בתשתית שלכם.

פונקציה קריפטוגרפית

כדי לבדוק אם קבוצת פרטי כניסה נפרצה, משתמשים בהגנה על סיסמאות כשיוצרים הערכות לפעולות כמו כניסות, שינויים בסיסמאות ואיפוס סיסמאות.

כדי לבדוק אם יש סיסמאות שנחשפו ופרטי כניסה שנפרצו, פועלים לפי השלבים הבאים:

  1. יצירת פרמטרים של בקשות.
  2. יצירת הערכה לזיהוי דליפות סיסמאות
  3. אימות פרטי כניסה שנחשפו בדליפה מתוך הערכה
  4. הסבר על פסק הדין ופעולות אפשריות

יצירת פרמטרים של בקשה

  1. חישוב פרמטרים נדרשים לבקשה באמצעות הפונקציות הקריפטוגרפיות שנדרשות על ידי פרוטוקול הפרטיות הגבוהה. ההגנה על הסיסמה מספקת ספריות 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();
    

    מערכי הבייטים lookupHashPrefix ו-encryptedUserCredentialsHash מכילים את הפרמטרים שנדרשים כדי להפעיל בדיקת סיסמאות Assessment.

יצירת הערכה לזיהוי דליפות סיסמאות

משתמשים בשיטה projects.assessments.create.

לפני שמשתמשים בנתוני הבקשה, צריך להחליף את הנתונים הבאים:

  • PROJECT_ID: מזהה הפרויקט ב- Google Cloud
  • LOOKUP_HASH_PREFIX: הקידומת של הגיבוב SHA-256 של שם המשתמש
  • ENCRYPTED_USER_CREDENTIALS_HASH: גיבוב Scrypt של פרטי כניסה מוצפנים של משתמש

ה-method של ה-HTTP וכתובת ה-URL:

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

אימות פרטי כניסה שנחשפו בהערכה

מתוך התשובה של ההערכה, שולפים את השדות reEncryptedUserCredentials ו-encryptedLeakMatchPrefixes ומעבירים אותם לאובייקט של הכלי לאימות כדי לקבוע אם פרטי הכניסה הודלפו או לא.

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

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

דוגמת קוד

‫Node.js (TypeScript)

כדי ללמוד איך להטמיע הגנה על סיסמאות באמצעות Node.js ‏ (TypeScript), אפשר לעיין בדוגמת הקוד של TypeScript ב-GitHub.

Java

כדי לבצע אימות ב-Fraud Defense, צריך להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לסביבת פיתוח מקומית.


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;

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 = verification.getLookupHashPrefix();
    byte[] encryptedUserCredentialsHash = 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 -> x.toByteArray())
            .collect(Collectors.toList());

    // Verify if the encrypted credentials are present in the obtained match list.
    PasswordCheckResult result =
        passwordLeak
            .verify(
                verification,
                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 במאגר. לאחר מכן, הקונטיינר מצפין את פרטי הכניסה האלה לפני שהוא שולח בקשת API, ומוודא שהתוצאה המוצפנת מחדש נכונה באופן מקומי.

כדי לשלוח בקשות למאגר Docker, מבצעים את השלבים הבאים:

  1. הגדרת Docker
  2. הכנת סביבה לקונטיינר Docker.
  3. יצירה והפעלה של הקונטיינר.
  4. שליחת בקשות HTTP למאגר התגים.
  5. הסבר על פסק הדין ופעולות אפשריות

הכנות להרצת קונטיינר Docker

  1. בוחרים שיטת אימות.

    הקונטיינר תומך בהגדרת Application Default Credentials או יכול לקבל מפתח API לצורך אימות.

  2. מגדירים את מאגר התגים של PLD כך שיפעל עם HTTPS או במצב הדגמה של localhost בלבד.

    מכיוון שהקונטיינר מקבל פרטי כניסה רגישים של משתמשי קצה (שמות משתמש וסיסמאות), צריך להריץ אותו באמצעות HTTPS או במצב הדגמה של localhost בלבד. הוראות להגדרת HTTPS זמינות בקובץ README ב-GitHub.

בשלבים הבאים נעשה שימוש באימות באמצעות מפתח 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
    

מאגר התגים מופעל ומתחיל לטפל בבקשות ביציאה 8080 של localhost.

שליחת בקשות ל-localhost

לפני שמשתמשים בנתוני הבקשה, צריך להחליף את הנתונים הבאים:

  • LEAKED_USERNAME: שם המשתמש של זוג פרטי הכניסה שנחשפו.
  • LEAKED_PASSWORD: הסיסמה של זוג פרטי הכניסה שדלפו.

ה-method של ה-HTTP וכתובת ה-URL:

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).

אם אתם לא משתמשים כבר באתר שלכם בספק MFA, אתם יכולים להשתמש ביכולת ה-MFA של Fraud Defense.

המאמרים הבאים