איך מוסיפים אימות רב-גורמי מסוג TOTP לאפליקציה ל-Android

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

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

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

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

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

  3. אם עדיין לא עשיתם זאת, אתם צריכים להתקין את Firebase Android SDK.

    אימות רב-שלבי באמצעות TOTP נתמך רק ב-Android SDK בגרסה v22.1.0 ומעלה.

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

כדי להפעיל סיסמה חד-פעמית מבוססת-זמן (TOTP) כגורם אימות שני, משתמשים ב-Admin SDK או קוראים לנקודת הקצה של ה-REST API להגדרת הפרויקט.

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

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

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

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

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

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

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

      TOTP פועלות כך שכאשר שני צדדים (המאמת והבודק) יוצרים OTP באותו חלון זמן (בדרך כלל 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: מספר המרווחים של חלון הזמן, מאפס עד עשר. ברירת המחדל היא חמש.

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

בחירת תבנית הרשמה

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

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

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

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

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

רישום משתמשים לאימות רב-שלבי באמצעות TOTP

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

  1. מאמתים מחדש את המשתמש.

  2. יצירת סוד TOTP עבור המשתמש המאומת:

    // Generate a TOTP secret.
    Firebase.auth.currentUser.multiFactor.session
        .addOnSuccessListener { multiFactorSession ->
            TotpMultiFactorGenerator.generateSecret(multiFactorSession)
                .addOnSuccessListener { totpSecret ->
                    // Display the secret to the user and prompt them to
                    // enter it into their authenticator app. (See the next
                    // step.)
                }
        }
    
  3. הצגת הסוד למשתמש והנחיה להזין אותו באפליקציה לאימות חשבונות:

    // Display this key:
    val secret = totpSecret.sharedSecretKey
    

    בנוסף להצגת המפתח הסודי, אפשר לנסות להוסיף אותו באופן אוטומטי לאפליקציה לאימות חשבונות שמוגדרת כברירת מחדל במכשיר. כדי לעשות זאת, צריך ליצור URI של מפתח שמתאים למאמת החשבונות של Google ולהעביר אותו אל openInOtpApp():

    val qrCodeUri = totpSecret.generateQrCodeUrl(
        currentUser.email ?: "default account",
        "Your App Name")
    totpSecret.openInOtpApp(qrCodeUri)
    

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

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

    // Ask the user for a verification code from the authenticator app.
    val verificationCode = // Code from user input.
    
    // Finalize the enrollment.
    val multiFactorAssertion = TotpMultiFactorGenerator
        .getAssertionForEnrollment(totpSecret, verificationCode)
    Firebase.auth.currentUser.multiFactor.enroll(multiFactorAssertion, "TOTP")
        .addOnSuccessListener {
            // Enrollment complete.
        }
    

כניסת משתמשים עם גורם שני

כדי להיכנס עם משתמשים באמצעות TOTP MFA, משתמשים בקוד הבא:

  1. מתקשרים לאחת מהשיטות של signInWith, כמו שהייתם עושים אם לא הייתם משתמשים באימות דו-שלבי. (לדוגמה, signInWithEmailAndPassword()). אם ה-method מחזיר FirebaseAuthMultiFactorException, מתחילים את תהליך האימות הרב-שלבי באפליקציה.

    Firebase.auth.signInWithEmailAndPassword(email, password)
        .addOnSuccessListener { result ->
            // 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.)
    
            // ...
        }
        .addOnFailureListener { exception ->
            when (exception) {
                is FirebaseAuthMultiFactorException -> {
                    // Initiate your second factor sign-in flow. (See next step.)
                    // ...
                }
            }
        }
    
  2. בתהליך האימות הרב-שלבי באפליקציה, המשתמש צריך קודם לבחור את הגורם השני שבו הוא רוצה להשתמש. כדי לקבל רשימה של אמצעי אימות דו-שלבי נתמכים, אפשר לבדוק את המאפיין hints של מופע MultiFactorResolver:

    val enrolledFactors = exception.resolver.hints.map { it.displayName }
    
  3. אם המשתמש בוחר להשתמש ב-TOTP, מבקשים ממנו להקליד את ה-TOTP שמוצג באפליקציית מאמת החשבונות שלו ולהשתמש בו כדי להיכנס:

    when (exception.resolver.hints[selectedIndex].factorId) {
        TotpMultiFactorGenerator.FACTOR_ID -> {
            val otpFromAuthenticator = // OTP typed by the user.
            val assertion = TotpMultiFactorGenerator.getAssertionForSignIn(
                exception.resolver.hints[selectedIndex].uid,
                otpFromAuthenticator
            )
            exception.resolver.resolveSignIn(assertion)
                .addOnSuccessListener { result ->
                    // Successfully signed in!
                }
                .addOnFailureListener { resolveError ->
                    // Invalid or expired OTP.
                }
        }
        PhoneMultiFactorGenerator.FACTOR_ID -> {
            // Handle SMS second factor.
        }
    }
    

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

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

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

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

Firebase.auth.currentUser.multiFactor.unenroll(mfaEnrollmentId)
    .addOnSuccessListener {
        // Second factor unenrolled.
    }
    .addOnFailureListener { exception ->
        when (exception) {
            is FirebaseAuthInvalidUserException -> {
                // Second factor unenrolled. 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.
                val credential = EmailAuthProvider.getCredential(email, password)
                currentUser.reauthenticate(credential)
                    .addOnSuccessListener { 
                        // Success!
                    }
                    .addOnFailureListener { 
                        // Bad email address and password combination.
                    }
            }
        }
    }

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