Dodaj uwierzytelnianie wielopoziomowe TOTP do swojej aplikacji internetowej

Jeśli korzystasz z wersji Firebase Authentication with Identity Platform, możesz dodać do aplikacji uwierzytelnianie wielopoziomowe (MFA) z hasłem jednorazowym generowanym na podstawie czasu (TOTP).

Firebase Authentication with Identity Platform umożliwia korzystanie z TOTP jako dodatkowego czynnika uwierzytelniania wieloskładnikowego. Gdy włączysz tę funkcję, użytkownicy, którzy spróbują zalogować się w aplikacji, zobaczą prośbę o wygenerowanie kodu TOTP. Aby wygenerować kod, muszą użyć aplikacji uwierzytelniającej, która umożliwia generowanie prawidłowych kodów TOTP, takiej jak Google Authenticator.

Zanim zaczniesz

  1. Włącz co najmniej 1 dostawcę, który obsługuje uwierzytelnianie wieloskładnikowe. Pamiętaj, że wszyscy dostawcy z wyjątkiem tych obsługują uwierzytelnianie wieloskładnikowe:

    • uwierzytelnianie przez telefon,
    • Anonimowe uwierzytelnianie
    • Niestandardowe tokeny uwierzytelniania
    • Apple Game Center
  2. Upewnij się, że aplikacja weryfikuje adresy e-mail użytkowników. MFA wymaga weryfikacji adresu e-mail. Zapobiega to rejestrowaniu się w usłudze za pomocą adresu e-mail, którego nie ma się na własność, a potem blokowaniu dostępu do niego rzeczywistemu właścicielowi adresu przez dodanie drugiego czynnika uwierzytelniania.

  3. Jeśli jeszcze tego nie zrobiono, zainstaluj pakiet SDK JavaScripta Firebase.

    TOTP MFA jest obsługiwany tylko w ramach modułowego pakietu SDK dla przeglądarki internetowej w wersji 9.19.1 lub nowszej.

Włączanie uwierzytelniania wieloskładniowego TOTP

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

Aby korzystać z Admin SDK:

  1. Jeśli jeszcze tego nie zrobiono, 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 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ąsiadujących przedziałów czasowych, z których mają być akceptowane tokeny TOTP, od 0 do 10. Wartość domyślna to 5.

      TOTP działają w taki sposób, że gdy obie strony (weryfikator i weryfikator) generują hasło jednorazowe w tym samym oknie czasowym (zwykle 30 sekund), generują to samo hasło. Jednak ze względu na różnice w czasie między stronami i czasie reakcji człowieka możesz skonfigurować usługę TOTP tak, aby akceptowała ona również TOTP z sąsiednich okien.

Aby włączyć uwierzytelnianie wieloskładnikowe TOTP za pomocą interfejsu REST API, wykonaj te czynności:

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 czasowych od 0 do 10. Wartość domyślna to 5.

    TOTP działają w taki sposób, że gdy obie strony (weryfikator i weryfikator) generują hasło jednorazowe w tym samym oknie czasowym (zwykle 30 sekund), generują to samo hasło. Jednak ze względu na różnice w czasie między stronami i czasie reakcji człowieka możesz skonfigurować usługę TOTP tak, aby akceptowała ona również TOTP z sąsiednich okien.

Wybieranie schematu rejestracji

Możesz wybrać, czy Twoja aplikacja wymaga uwierzytelniania wielopoziomowego, a także sposób i moment rejestracji użytkowników. Oto kilka typowych wzorców:

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

  • Zaoferować możliwą do pominięcia opcję rejestracji drugiego składnika podczas rejestracji. Jeśli chcesz zachęcać użytkowników do korzystania z uwierzytelniania wielopoziomowego, ale nie wymagać tego, możesz zastosować to rozwiązanie.

  • Dodanie możliwości dodawania drugiego czynnika na koncie użytkownika lub na stronie zarządzania profilem zamiast na ekranie rejestracji. Pozwala to zminimalizować trudności podczas procesu rejestracji, a jednocześnie udostępnia uwierzytelnianie wielopoziomowe użytkownikom, którzy przykładają dużą wagę do bezpieczeństwa.

  • Wymagaj stopniowego dodawania drugiego składnika, 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 uwierzytelniania wieloskładnikowego TOTP jako drugiego poziomu uwierzytelniania w aplikacji wprowadź logikę po stronie klienta, aby rejestrować użytkowników w ramach uwierzytelniania wieloskładnikowego TOTP:

  1. Zaimportuj wymagane klasy i funkcje MFA:

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

  3. Wygeneruj 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 klucz tajny użytkownikowi i poproś go o jego wpisanie w aplikacji uwierzytelniającej.

    W wielu aplikacjach uwierzytelniających użytkownicy mogą szybko dodawać nowe sekrety TOTP, skanując kod QR, który reprezentuje identyfikator URI klucza zgodny z aplikacją Google Authenticator. Aby wygenerować kod QR do tego celu, wygeneruj identyfikator URI za pomocą funkcji generateQrCodeUrl(), a następnie zakoduj go za pomocą 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 klucz tajny, 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 tajny klucz do aplikacji uwierzytelniającej, zacznie ona generować TOTP.

  5. Poproś użytkownika o wpisanie TOTP wyświetlonego w aplikacji uwierzytelniającej i użyj go do sfinalizowania rejestracji w wielostopniowym uwierzytelnieniu:

    // 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 w taki sam sposób, jak w przypadku nieużywania MFA. (np. signInWithEmailAndPassword()). Jeśli metoda zwróci błądauth/multi-factor-auth-required, uruchom proces uwierzytelniania dwuetapowego w 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. W ramach procesu uwierzytelniania dwuskładnikowego aplikacja powinna najpierw poprosić użytkownika o wybranie drugiego czynnika. Listę obsługiwanych drugich czynników znajdziesz, sprawdzają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ć protokołu TOTP, poproś go o wpisanie TOTP wyświetlonego w aplikacji uwierzytelniającej i użycie go do logowania:

    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 wielostopniowej weryfikacji tożsamości z użyciem klucza bezpieczeństwa TOTP

W tej sekcji opisano, jak postępować w przypadku wyrejestrowania użytkownika z wielostopniowej weryfikacji tożsamości TOTP.

Jeśli użytkownik korzysta z kilku opcji uwierzytelniania wielopoziomowego i rezygnuje z najnowszej z nich, otrzyma auth/user-token-expiredi zostanie wylogowany. Użytkownik musi się ponownie zalogować i potwierdzić swoje dotychczasowe dane logowania, np. adres e-mail i hasło.

Aby wyrejestrować użytkownika, naprawić 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?