הוספת אימות רב-גורמי מסוג TOTP לאפליקציית האינטרנט

אם שדרגתם ל-Firebase Authentication with Identity Platform, תוכלו להוסיף לאפליקציה אימות רב-שלבי (MFA) באמצעות סיסמה חד-פעמית מבוססת-זמן (TOTP).

Firebase Authentication with Identity Platform מאפשר להשתמש ב-TOTP כגורם נוסף לאימות רב-שלבי. כשמפעילים את התכונה הזו, משתמשים שמנסים להיכנס לאפליקציה יראו בקשה ל-TOTP. כדי ליצור אותו, הם צריכים להשתמש באפליקציית אימות שיכולה ליצור קודי TOTP תקפים, כמו מאמת החשבונות של Google.

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

  1. מפעילים ספק אחד לפחות שתומך ב-MFA. חשוב לזכור שכל הספקים למעט הספקים הבאים תומכים באימות דו-שלבי:

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

  3. אם עדיין לא עשיתם זאת, מתקינים את Firebase JavaScript SDK.

    TOTP MFA נתמך רק במודולרי Web SDK, גרסאות 9.19.1 ומעלה.

הפעלת אימות דו-שלבי באמצעות TOTP

כדי להפעיל את TOTP כגורם שני, משתמשים ב-Admin SDK או קוראים לנקודת הקצה של ה-REST של הגדרות הפרויקט.

כדי להשתמש ב-Admin SDK:

  1. אם עדיין לא עשיתם זאת, מתקינים את ה-SDK של Firebase Admin עבור Node.js.

    יש תמיכה בשיטת האימות הדו-שלבי באמצעות TOTP רק ב-SDK של Firebase Admin עבור Node.js בגרסה 11.6.0 ואילך.

  2. מריצים את הפקודה הבאה:

    import { getAuth } from 'firebase-admin/auth';
    
    getAuth().projectConfigManager().updateProjectConfig(
    {
          multiFactorConfig: {
              providerConfigs: [{
                  state: "ENABLED",
                  totpProviderConfig: {
                      adjacentIntervals: NUM_ADJ_INTERVALS
                  }
              }]
          }
    })
    

    מחליפים את מה שכתוב בשדות הבאים:

    • NUM_ADJ_INTERVALS: מספר חלונות הזמן הסמוכים שבהם אפשר לקבל אסימוני TOTP, מ-0 עד 10. ברירת המחדל היא חמש.

      המפתחות החד-פעמיים מבוססי TOTP פועלים כך: כששני צדדים (המוכיח והמאמת) יוצרים מפתחות חד-פעמיים באותו חלון זמן (בדרך כלל 30 שניות), הם יוצרים את אותה סיסמה. עם זאת, כדי להתאים את השעון בין הצדדים לזמן התגובה של האדם, אפשר להגדיר את שירות ה-TOTP כך שיקבל גם אסימוני TOTP מחלונות סמוכים.

כדי להפעיל אימות דו-שלבי באמצעות TOTP באמצעות ה-API ל-REST, מריצים את הפקודה הבאה:

curl -X PATCH "https://identitytoolkit.googleapis.com/admin/v2/projects/PROJECT_ID/config?updateMask=mfa" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    -H "Content-Type: application/json" \
    -H "X-Goog-User-Project: PROJECT_ID" \
    -d \
    '{
        "mfa": {
          "providerConfigs": [{
            "state": "ENABLED",
            "totpProviderConfig": {
              "adjacentIntervals": NUM_ADJ_INTERVALS
            }
          }]
       }
    }'

מחליפים את מה שכתוב בשדות הבאים:

  • PROJECT_ID: מזהה הפרויקט.
  • NUM_ADJ_INTERVALS: מספר פרקי הזמן בחלון הזמן, מאפס עד עשר. ערך ברירת המחדל הוא 5.

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

בחירת דפוס ההרשמה

אתם יכולים לבחור אם האפליקציה תחייב אימות רב-שלבי, ואיך ומתי להירשם המשתמשים. דוגמאות לדפוסים נפוצים:

  • רישום הגורם השני של המשתמש כחלק מהרישום. כדאי להשתמש בשיטה הזו אם האפליקציה שלכם דורשת אימות רב-שלבי לכל המשתמשים.

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

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

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

רישום משתמשים ב-TOTP MFA

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

  1. מייבאים את המחלקות והפונקציות הנדרשות של MFA:

    import {
      multiFactor,
      TotpMultiFactorGenerator,
      TotpSecret,
      getAuth,
    } from "firebase/auth";
    
  2. מבצעים אימות מחדש של המשתמש.

  3. יוצרים סוד TOTP למשתמש המאומת:

    // Generate a TOTP secret.
    const multiFactorSession = await multiFactor(currentUser).getSession();
    const totpSecret = await TotpMultiFactorGenerator.generateSecret(
      multiFactorSession
    );
    
  4. מציגים את הסוד למשתמש ומבקשים ממנו להזין אותו באפליקציית האימות שלו.

    באפליקציות אימות רבות, המשתמשים יכולים להוסיף במהירות סודות TOTP חדשים על ידי סריקת קוד QR שמייצג URI של מפתח תואם ל-Google Authenticator. כדי ליצור קוד QR למטרה הזו, יוצרים את ה-URI באמצעות generateQrCodeUrl() ואז מקודדים אותו באמצעות ספריית קודי ה-QR הרצויה. לדוגמה:

    const totpUri = totpSecret.generateQrCodeUrl(
        currentUser.email,
        "Your App's Name"
    );
    await QRExampleLib.toCanvas(totpUri, qrElement);
    

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

    // Also display this key:
    const secret = totpSecret.secretKey;
    

    אחרי שהמשתמש יוסיף את הסוד שלו לאפליקציה לאימות חשבונות, המכשיר יתחיל ליצור TOTPs.

  5. מבקשים מהמשתמש להקליד את ה-TOTP שמוצג באפליקציה לאימות החשבונות ולהשתמש בו כדי להשלים את ההרשמה ל-MFA:

    // Ask the user for a verification code from the authenticator app.
    const verificationCode = // Code from user input.
    
    // Finalize the enrollment.
    const multiFactorAssertion = TotpMultiFactorGenerator.assertionForEnrollment(
      totpSecret,
      verificationCode
    );
    await multiFactor(currentUser).enroll(multiFactorAssertion, mfaDisplayName);
    

כניסה של משתמשים באמצעות גורם אימות שני

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

  1. מייבאים את הכיתות והפונקציות הנדרשות של אימות דו-שלבי:

    import {
        getAuth,
        getMultiFactorResolver,
        TotpMultiFactorGenerator,
    } from "firebase/auth";
    
  2. קוראים לאחת מהשיטות עם signInWith כמו שאתם עושים אם אתם לא משתמשים בשיטת אימות דו-שלבי. (לדוגמה, signInWithEmailAndPassword()). אם השיטה מחזירה את השגיאה auth/multi-factor-auth-required, מתחילים את תהליך האימות הדו-שלבי של האפליקציה.

    try {
        const userCredential = await signInWithEmailAndPassword(
            getAuth(),
            email,
            password
        );
        // If the user is not enrolled with a second factor and provided valid
        // credentials, sign-in succeeds.
    
        // (If your app requires MFA, this could be considered an error
        // condition, which you would resolve by forcing the user to enroll a
        // second factor.)
    
        // ...
    } catch (error) {
        switch (error.code) {
            case "auth/multi-factor-auth-required":
                // Initiate your second factor sign-in flow. (See next step.)
                // ...
                break;
            case ...:  // Handle other errors, such as wrong passwords.
                break;
        }
    }
    
  3. בתהליך האימות הדו-שלבי של האפליקציה, המשתמש צריך לבחור קודם את הגורם השני שבו הוא רוצה להשתמש. כדי לקבל רשימה של גורמים נוספים שנתמכים, תוכלו לבחון את המאפיין hints של מכונה MultiFactorResolver:

    const mfaResolver = getMultiFactorResolver(getAuth(), error);
    const enrolledFactors = mfaResolver.hints.map(info => info.displayName);
    
  4. אם המשתמש בוחר להשתמש ב-TOTP, מבקשים ממנו להקליד את ה-TOTP שמוצג באפליקציית האימות שלו ולהשתמש בו כדי להיכנס:

    switch (mfaResolver.hints[selectedIndex].factorId) {
        case TotpMultiFactorGenerator.FACTOR_ID:
            const otpFromAuthenticator = // OTP typed by the user.
            const multiFactorAssertion =
                TotpMultiFactorGenerator.assertionForSignIn(
                    mfaResolver.hints[selectedIndex].uid,
                    otpFromAuthenticator
                );
            try {
                const userCredential = await mfaResolver.resolveSignIn(
                    multiFactorAssertion
                );
                // Successfully signed in!
            } catch (error) {
                // Invalid or expired OTP.
            }
            break;
        case PhoneMultiFactorGenerator.FACTOR_ID:
            // Handle SMS second factor.
            break;
        default:
            // Unsupported second factor?
            break;
    }
    

ביטול ההרשמה לאימות דו-שלבי באמצעות TOTP

בקטע הזה מוסבר איך מטפלים במצב שבו משתמש מבטל את ההרשמה ל-MFA באמצעות TOTP.

אם משתמש נרשם לכמה אפשרויות של אימות דו-שלבי, והוא מבטל את ההרשמה מהאפשרות שהופעל לאחרונה, הוא יקבל הודעת auth/user-token-expired והוא יוסר מהחשבון. המשתמש צריך להיכנס שוב ולאמת את פרטי הכניסה הקיימים שלו – למשל, כתובת אימייל וסיסמה.

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

import {
    EmailAuthProvider,
    TotpMultiFactorGenerator,
    getAuth,
    multiFactor,
    reauthenticateWithCredential,
} from "firebase/auth";

try {
    // Unenroll from TOTP MFA.
    await multiFactor(currentUser).unenroll(mfaEnrollmentId);
} catch  (error) {
    if (error.code === 'auth/user-token-expired') {
        // If the user was signed out, re-authenticate them.

        // For example, if they signed in with a password, prompt them to
        // provide it again, then call `reauthenticateWithCredential()` as shown
        // below.

        const credential = EmailAuthProvider.credential(email, password);
        await reauthenticateWithCredential(
            currentUser,
            credential
        );
    }
}

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