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

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

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

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

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

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

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

    אימות רב-שלבי באמצעות TOTP נתמך רק ב-Apple SDK בגרסה v10.12.0 ומעלה, ורק ב-iOS.

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

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

כדי להשתמש ב-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.

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

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

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

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

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

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

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

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

הרשמה של משתמשים לאימות רב-שלבי (MFA) באמצעות TOTP

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

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

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

    // Generate a TOTP secret.
    guard let mfaSession = try? await currentUser.multiFactor.session() else { return }
    guard let totpSecret = try? await TOTPMultiFactorGenerator.generateSecret(with: mfaSession) else { return }
    
    // Display the secret to the user and prompt them to enter it into their
    // authenticator app. (See the next step.)
    
  3. הצגת הסוד למשתמש והנחיה להזין אותו באפליקציית האימות:

    // Display this key:
    let secret = totpSecret.sharedSecretKey()
    

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

    let otpAuthUri = totpSecret.generateQRCodeURL(
        withAccountName: currentUser.email ?? "default account",
        issuer: "Your App Name")
    totpSecret.openInOTPApp(withQRCodeURL: otpAuthUri)
    

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

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

    // Ask the user for a verification code from the authenticator app.
    let verificationCode = // Code from user input.
    
    // Finalize the enrollment.
    let multiFactorAssertion = TOTPMultiFactorGenerator.assertionForEnrollment(
        with: totpSecret,
        oneTimePassword: verificationCode)
    do {
        try await currentUser.multiFactor.enroll(
            with: multiFactorAssertion,
            displayName: "TOTP")
    } catch {
        // Wrong or expired OTP. Re-prompt the user.
    }
    

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

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

  1. קוראים לאחת מהשיטות signIn(with...:)- כמו שהייתם עושים אם לא הייתם משתמשים באימות דו-שלבי (לדוגמה, signIn(withEmail:password:)). אם השיטה מחזירה שגיאה עם הקוד secondFactorRequired, מתחילים את תהליך האימות הדו-שלבי של האפליקציה.

    do {
        let authResult = try await Auth.auth().signIn(withEmail: email, password: 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 let error as AuthErrorCode where error.code == .secondFactorRequired {
        // Initiate your second factor sign-in flow. (See next step.)
        // ...
    } catch {
        // Other auth error.
        throw error
    }
    
  2. בתהליך האימות הרב-שלבי באפליקציה, המשתמש צריך קודם לבחור את הגורם השני שבו הוא רוצה להשתמש. כדי לקבל רשימה של אמצעי אימות דו-שלבי נתמכים, אפשר לבדוק את המאפיין hints של מופע MultiFactorResolver:

    let mfaKey = AuthErrorUserInfoMultiFactorResolverKey
    guard let resolver = error.userInfo[mfaKey] as? MultiFactorResolver else { return }
    let enrolledFactors = resolver.hints.map(\.displayName)
    
  3. אם המשתמש בוחר להשתמש ב-TOTP, מבקשים ממנו להקליד את ה-TOTP שמוצג באפליקציית מאמת החשבונות שלו ולהשתמש בו כדי להיכנס:

    let multiFactorInfo = resolver.hints[selectedIndex]
    switch multiFactorInfo.factorID {
    case TOTPMultiFactorID:
        let otpFromAuthenticator = // OTP typed by the user.
        let assertion = TOTPMultiFactorGenerator.assertionForSignIn(
            withEnrollmentID: multiFactorInfo.uid,
            oneTimePassword: otpFromAuthenticator)
        do {
            let authResult = try await resolver.resolveSignIn(with: assertion)
        } catch {
            // Wrong or expired OTP. Re-prompt the user.
        }
    default:
        return
    }
    

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

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

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

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

guard let currentUser = Auth.auth().currentUser else { return }

// Prompt the user to select a factor to unenroll, from this array:
currentUser.multiFactor.enrolledFactors

// ...

// Unenroll the second factor.
let multiFactorInfo = currentUser.multiFactor.enrolledFactors[selectedIndex]
do {
    try await currentUser.multiFactor.unenroll(with: multiFactorInfo)
} catch let error as AuthErrorCode where error.code == .invalidUserToken {
    // Second factor unenrolled, but the user was signed out. Re-authenticate
    // them.
}

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