Dodaj uwierzytelnianie wielopoziomowe TOTP do swojej aplikacji internetowej

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 JavaScript, jeśli jeszcze go nie masz.

    Protokół TOTP MFA jest obsługiwany tylko w modułowym pakiecie Web SDK w wersji 9.19.1 lub nowszej.

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. Zaimportuj wymagane klasy i funkcje MFA:

    import {
      multiFactor,
      TotpMultiFactorGenerator,
      TotpSecret,
      getAuth,
    } from "firebase/auth";
    
  2. Ponownie uwierzytelnij użytkownika.

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

    // Generate a TOTP secret.
    const multiFactorSession = await multiFactor(currentUser).getSession();
    const totpSecret = await TotpMultiFactorGenerator.generateSecret(
      multiFactorSession
    );
    
  4. Wyświetl tajny klucz użytkownikowi i poproś go o wpisanie go w aplikacji uwierzytelniania.

    W wielu aplikacjach uwierzytelniających użytkownicy mogą szybko dodawać nowe obiekty tajne TOTP, skanując kod QR reprezentujący identyfikator URI klucza zgodny z Google Authenticator. Aby wygenerować kod QR w tym celu, wygeneruj identyfikator URI przy użyciu generateQrCodeUrl(), a potem zakoduj go, korzystając z wybranej biblioteki kodów QR. Przykład:

    const totpUri = totpSecret.generateQrCodeUrl(
        currentUser.email,
        "Your App's Name"
    );
    await QRExampleLib.toCanvas(totpUri, qrElement);
    

    Niezależnie od tego, czy wyświetlasz kod QR, zawsze wyświetlaj tajny klucz, aby obsługiwać aplikacje uwierzytelniające, które nie mogą odczytywać kodów QR:

    // Also display this key:
    const secret = totpSecret.secretKey;
    

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

  5. Poproś użytkownika o wpisanie TOTP wyświetlanego w aplikacji uwierzytelniającej i użycie go do sfinalizowania rejestracji MFA:

    // Ask the user for a verification code from the authenticator app.
    const verificationCode = // Code from user input.
    
    // Finalize the enrollment.
    const multiFactorAssertion = TotpMultiFactorGenerator.assertionForEnrollment(
      totpSecret,
      verificationCode
    );
    await multiFactor(currentUser).enroll(multiFactorAssertion, mfaDisplayName);
    

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

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

  1. Zaimportuj wymagane klasy i funkcje MFA:

    import {
        getAuth,
        getMultiFactorResolver,
        TotpMultiFactorGenerator,
    } from "firebase/auth";
    
  2. Wywołaj jedną z metod signInWith-, tak jak w przypadku braku MFA. (np. signInWithEmailAndPassword()). Jeśli metoda spowoduje zgłoszenie błędu auth/multi-factor-auth-required, uruchom proces MFA aplikacji.

    try {
        const userCredential = await signInWithEmailAndPassword(
            getAuth(),
            email,
            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 (error) {
        switch (error.code) {
            case "auth/multi-factor-auth-required":
                // Initiate your second factor sign-in flow. (See next step.)
                // ...
                break;
            case ...:  // Handle other errors, such as wrong passwords.
                break;
        }
    }
    
  3. 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:

    const mfaResolver = getMultiFactorResolver(getAuth(), error);
    const enrolledFactors = mfaResolver.hints.map(info => info.displayName);
    
  4. 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:

    switch (mfaResolver.hints[selectedIndex].factorId) {
        case TotpMultiFactorGenerator.FACTOR_ID:
            const otpFromAuthenticator = // OTP typed by the user.
            const multiFactorAssertion =
                TotpMultiFactorGenerator.assertionForSignIn(
                    mfaResolver.hints[selectedIndex].uid,
                    otpFromAuthenticator
                );
            try {
                const userCredential = await mfaResolver.resolveSignIn(
                    multiFactorAssertion
                );
                // Successfully signed in!
            } catch (error) {
                // Invalid or expired OTP.
            }
            break;
        case PhoneMultiFactorGenerator.FACTOR_ID:
            // Handle SMS second factor.
            break;
        default:
            // Unsupported second factor?
            break;
    }
    

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:

import {
    EmailAuthProvider,
    TotpMultiFactorGenerator,
    getAuth,
    multiFactor,
    reauthenticateWithCredential,
} from "firebase/auth";

try {
    // Unenroll from TOTP MFA.
    await multiFactor(currentUser).unenroll(mfaEnrollmentId);
} catch  (error) {
    if (error.code === 'auth/user-token-expired') {
        // 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.

        const credential = EmailAuthProvider.credential(email, password);
        await reauthenticateWithCredential(
            currentUser,
            credential
        );
    }
}

Co dalej?