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

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

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

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

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

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

  3. אם עדיין לא עשיתם זאת, התקינו את Firebase Android SDK.

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

הפעלת אימות TOTP MFA

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

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

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

    אימות TOTP MFA נתמך רק ב-Firebase Admin Node.js SDK בגרסה 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, מאפס עד עשר. ערך ברירת המחדל הוא 5.

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

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

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

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

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

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

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

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

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

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

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

אם משתמש נרשם לכמה אפשרויות של MFA, והוא מבטל את ההרשמה לאפשרות שהופעלה לאחרונה, הוא מקבל 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.
                    }
            }
        }
    }

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