Dodawanie uwierzytelniania wielopoziomowego TOTP do aplikacji na Androida

Po przejściu na Uwierzytelnianie Firebase z Identity Platform możesz dodać hasło jednorazowe na czas. uwierzytelnianie wielopoziomowe (MFA) aplikacji (TOTP).

Uwierzytelnianie Firebase na platformie Identity Platform umożliwia stosowanie TOTP jako dodatkowego czynnika uwierzytelniania MFA. Gdy włącz tę funkcję, użytkownicy próbujący zalogować się w Twojej aplikacji zobaczą TOTP. Aby go wygenerować, musi użyć aplikacji uwierzytelniającej, która potrafi wygenerować prawidłowe kody TOTP, np. 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ących MFA:

    • Uwierzytelnianie telefonu
    • Anonimowe uwierzytelnianie
    • Niestandardowe tokeny uwierzytelniania
    • Apple Game Center
  2. Upewnij się, że aplikacja weryfikuje adresy e-mail użytkowników. MFA wymaga adresu e-mail weryfikacji. Dzięki temu hakerzy nie będą mogli zarejestrować się w usłudze za pomocą cudzego adresu e-mail, a następnie zablokować właściciela adresu e-mail, dodając drugi składnik.

  3. Zainstaluj Pakiet SDK Firebase na Androida.

    Protokół TOTP MFA jest obsługiwany tylko w Pakiet SDK na Androida w wersji 22.1.0 i innych.

Włącz TOTP MFA

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

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

  1. Zainstaluj Pakiet SDK Firebase Admin Node.js.

    Protokół TOTP MFA jest obsługiwany tylko przez pakiet SDK Firebase Admin Node.js w wersji 11.6.0 oraz powyżej.

  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ąsiadujących ze sobą przedziały czasu, w których mają być akceptowane hasła TOTP, od 0 do 10. domyślna wartość to 5.

      Skrypty TOTP działają tak, aby, gdy dwie strony (zalecający i walidatorowi) generować hasła jednorazowe w tym samym przedziale czasu (zwykle 30 sekund, generują to samo hasło. Jednak aby dostosować jeśli występują różnice między podmiotami a czasem reakcji ludzi, możesz skonfigurować TOTP aby akceptować także TOTP z sąsiednich okien.

Aby włączyć TOTP MFA 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 w odstępach czasowych od 0 do 10. Wartością domyślną jest 5.

    Skrypty TOTP działają tak, aby, gdy dwie strony (zalecający i walidatorowi) generować hasła jednorazowe w tym samym przedziale czasu (zwykle 30 sekund, generują to samo hasło. Jednak aby dostosować jeśli występują różnice między podmiotami a czasem reakcji ludzi, możesz skonfigurować TOTP aby akceptować także TOTP z sąsiednich okien.

Wybierz wzorzec rejestracji

Możesz zdecydować, czy Twoja aplikacja wymaga uwierzytelniania wielopoziomowego i w jaki sposób i kiedy zarejestrować użytkowników. Oto niektóre typowe wzorce:

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

  • Zaoferować możliwą do pominięcia opcję rejestracji drugiego składnika podczas rejestracji. Jeśli chcesz zachęcić do uwierzytelniania wielopoziomowego w aplikacji, ale nie wymagać od Ciebie jej stosowania, może zastosować tę metodę.

  • umożliwia dodanie drugiego składnika z konta lub profilu użytkownika. na stronie zarządzania, a nie na ekranie rejestracji. Pozwala to zminimalizować tarcie podczas rejestracji, a jednocześnie stosować uwierzytelnianie dwuskładnikowe. dostępna dla użytkowników, którzy zwracają uwagę na bezpieczeństwo.

  • Wymagaj stopniowego dodawania drugiego składnika, gdy użytkownik chce uzyskać dostęp funkcje o wyższych wymaganiach w zakresie bezpieczeństwa.

Rejestrowanie użytkowników w TOTP MFA

Po włączeniu protokołu TOTP MFA jako drugiego składnika w aplikacji wdróż konfigurację po stronie klienta logic do rejestrowania użytkowników w TOTP MFA:

  1. Ponownie uwierzytelnij użytkownika.

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

    // 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. Wyświetl użytkownikowi tajny klucz i poproś go o jego podanie aplikacja uwierzytelniająca:

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

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

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

    Gdy użytkownik doda swój tajny klucz do aplikacji uwierzytelniającej, zostanie uruchomiony i generowanie tagów TOTP.

  4. użytkownik musi wpisać TOTP wyświetlony w aplikacji uwierzytelniającej, użyj go, aby zakończyć rejestrację 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.
        }
    

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 signInWith w taki sam sposób, jak w przypadku nieużywania MFA. (np. signInWithEmailAndPassword()). Jeśli metoda zwróci błąd FirebaseAuthMultiFactorException, rozpocznij proces MFA aplikacji.

    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. Procedura MFA aplikacji powinna najpierw zachęcić użytkownika do wyboru drugiego składnika których nie chce używać. Listę obsługiwanych drugich czynników możesz sprawdzić, badanie właściwości hints instancji MultiFactorResolver:

    val enrolledFactors = exception.resolver.hints.map { it.displayName }
    
  3. Jeśli użytkownik zdecyduje się na użycie protokołu TOTP, poproś go o wpisanie tagu TOTP wyświetlanego na stronie jej aplikację uwierzytelniającą i użyć jej do zalogowania się:

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

Wyrejestruj się z TOTP MFA

Ta sekcja zawiera informacje o tym, jak postępować w przypadku użytkownika wyrejestrującego się z TOTP MFA.

Jeśli użytkownik zarejestrował się w wielu opcjach MFA i jeśli się wyrejestrował wybierając spośród ostatnio włączonej opcji, otrzyma auth/user-token-expired i są wylogowani. Użytkownik będzie musiał zalogować się ponownie i potwierdzić swoje konto istniejących danych logowania, takich jak adres e-mail i hasło.

Aby wyrejestrować użytkownika, naprawić błąd i aktywować ponowne uwierzytelnianie, skorzystaj z ten kod:

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

Co dalej?