Dodaj uwierzytelnianie wielopoziomowe TOTP do swojej aplikacji na iOS

Po przejściu na Uwierzytelnianie Firebase z Identity Platform możesz dodać do swojej aplikacji uwierzytelnianie wielopoziomowe z użyciem hasła jednorazowego (TOTP).

Uwierzytelnianie Firebase z Identity Platform umożliwia użycie TOTP jako dodatkowego czynnika w przypadku MFA. Gdy włączysz tę funkcję, użytkownicy próbujący zalogować się w aplikacji zobaczą prośbę o podanie hasła TOTP. Aby go wygenerować, należy użyć aplikacji uwierzytelniającej, która generuje prawidłowe kody TOTP, na przykład Google Authenticator.

Zanim zaczniesz

  1. Włącz co najmniej 1 dostawcę, który obsługuje MFA. Pamiętaj, że wszyscy dostawcy oprócz tych obsługują MFA:

    • Uwierzytelnianie przez telefon
    • Anonimowe uwierzytelnianie
    • Niestandardowe tokeny uwierzytelniania
    • Centrum gier Apple
  2. Upewnij się, że Twoja aplikacja weryfikuje adresy e-mail użytkowników. MFA wymaga weryfikacji adresu e-mail. Dzięki temu niepowołane osoby nie będą mogły zarejestrować się w usłudze za pomocą adresu e-mail, który nie należą do nich, a następnie zablokują faktycznego właściciela adresu e-mail przez dodanie drugiego składnika.

  3. Zainstaluj pakiet SDK Firebase Apple, jeśli jeszcze go nie masz.

    Protokół TOTP MFA jest obsługiwany tylko w pakiecie Apple SDK w wersji 10.12.0 lub nowszej oraz na urządzeniach z iOS.

Włącz TOTP MFA

Aby włączyć TOTP jako drugi czynnik, użyj pakietu Admin SDK lub wywołaj punkt końcowy REST konfiguracji projektu.

Aby użyć pakietu Admin SDK, wykonaj te czynności:

  1. Zainstaluj pakiet SDK Firebase Admin Node.js, jeśli jeszcze go nie masz.

    Protokół TOTP MFA jest obsługiwany tylko w pakiecie SDK Firebase Admin Node.js w wersji 11.6.0 lub nowszej.

  2. Wykonaj zapytanie:

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

    Zastąp następujące elementy:

    • NUM_ADJ_INTERVALS: liczba sąsiednich przedziałów czasu, od 0 do 10 przedziałów czasu, od których przyjmuje się TOTP. Wartością domyślną jest 5.

      Wykonawcy TOTP zapewniają, że gdy 2 strony (weryfikator i walidator) generują hasła jednorazowe w tym samym przedziale czasu (zazwyczaj 30 sekund), generują to samo hasło. Jednak aby uwzględnić drgania zegara między stronami i czas reakcji pracowników, możesz skonfigurować usługę TOTP tak, aby akceptowała TOTP także z sąsiednich okien.

Aby włączyć uwierzytelnianie typu TOTP za pomocą interfejsu API REST, uruchom to polecenie:

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

Zastąp następujące elementy:

  • PROJECT_ID: identyfikator projektu.
  • NUM_ADJ_INTERVALS: liczba przedziałów czasu, od 0 do 10. Wartością domyślną jest 5.

    Wykonawcy TOTP zapewniają, że gdy 2 strony (weryfikator i walidator) generują hasła jednorazowe w tym samym przedziale czasu (zazwyczaj 30 sekund), generują to samo hasło. Jednak aby uwzględnić drgania zegara między stronami i czas reakcji pracowników, możesz skonfigurować usługę TOTP tak, aby akceptowała TOTP także z sąsiednich okien.

Wybierz wzorzec rejestracji

Możesz określić, czy Twoja aplikacja wymaga uwierzytelniania wielopoziomowego oraz jak i kiedy rejestrować użytkowników. Oto niektóre typowe wzorce:

  • Zarejestruj drugi składnik uwierzytelniania użytkownika w ramach rejestracji. Użyj tej metody, jeśli Twoja aplikacja wymaga uwierzytelniania wielopoziomowego dla wszystkich użytkowników.

  • Zaproponuj możliwość pominięcia uwierzytelniania dwuskładnikowego podczas rejestracji. Jeśli chcesz zachęcić użytkowników do korzystania z uwierzytelniania wielopoziomowego w swojej aplikacji, ale nie wymagać go, możesz wykorzystać tę metodę.

  • Daj możliwość dodania drugiego składnika na stronie zarządzania kontem lub profilem użytkownika zamiast na ekranie rejestracji. Pozwala to zminimalizować błędy podczas rejestracji i jednocześnie udostępniać uwierzytelnianie wielopoziomowe użytkownikom, którzy zwracają szczególną uwagę na bezpieczeństwo.

  • Wymagaj stopniowego dodawania drugiego czynnika, gdy użytkownik chce uzyskać dostęp do funkcji o wyższych wymaganiach w zakresie bezpieczeństwa.

Rejestrowanie użytkowników w TOTP MFA

Po włączeniu MFA TOTP jako drugiego etapu w aplikacji zaimplementuj logikę po stronie klienta, aby rejestrować użytkowników w TOTP MFA:

  1. Ponownie uwierzytelnij użytkownika.

  2. Wygeneruj tajny klucz TOTP dla uwierzytelnionego użytkownika:

    // 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. Wyświetl użytkownikowi tajny klucz i poproś go o wpisanie go w aplikacji uwierzytelniania:

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

    Oprócz wyświetlenia tajnego klucza możesz też spróbować automatycznie dodać go do domyślnej aplikacji uwierzytelniającej na urządzeniu. Aby to zrobić, wygeneruj identyfikator URI klucza zgodny z Google Authenticator i przekaż go openInOTPApp(withQRCodeURL:):

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

    Gdy użytkownik doda swój tajny klucz do aplikacji uwierzytelniającej, zacznie ona generować żądania TOTP.

  4. Poproś użytkownika o wpisanie hasła TOTP wyświetlanego w aplikacji uwierzytelniającej i użyj go do sfinalizowania rejestracji MFA:

    // 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.
    }
    

Logowanie użytkowników za pomocą drugiego składnika

Aby zalogować użytkowników za pomocą TOTP MFA, użyj tego kodu:

  1. Wywołaj jedną z metod signIn(with...:)- tak jak w przypadku, gdy nie używasz MFA (np. signIn(withEmail:password:)). Jeśli metoda spowoduje błąd z kodem secondFactorRequired, uruchom przepływ MFA aplikacji.

    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. Proces MFA aplikacji powinien najpierw poprosić użytkownika o wybranie drugiego czynnika, którego chce użyć. Listę obsługiwanych drugich czynników możesz uzyskać, analizując właściwość hints instancji MultiFactorResolver:

    let mfaKey = AuthErrorUserInfoMultiFactorResolverKey
    guard let resolver = error.userInfo[mfaKey] as? MultiFactorResolver else { return }
    let enrolledFactors = resolver.hints.map(\.displayName)
    
  3. Jeśli użytkownik zdecyduje się używać TOTP, poproś go o wpisanie tego hasła wyświetlanego w aplikacji uwierzytelniającej i użyj go do zalogowania:

    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
    }
    

Wyrejestrowanie z TOTP MFA

Ta sekcja opisuje, jak postępować w przypadku wyrejestrowania się przez użytkownika z TOTP MFA.

Jeśli użytkownik zarejestrował się w kilku opcjach MFA i wyrejestrował się z ostatnio włączonej opcji, otrzyma auth/user-token-expired i zostanie wylogowany. Użytkownik musi zalogować się ponownie i potwierdzić swoje dotychczasowe dane logowania, takie jak adres e-mail i hasło.

Aby wyrejestrować użytkownika, obsłużyć błąd i aktywować ponowne uwierzytelnianie, użyj tego kodu:

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

Co dalej?