Добавьте многофакторную аутентификацию TOTP в свое веб-приложение.

Если вы обновили Firebase Authentication with Identity Platform , вы можете добавить в свое приложение многофакторную аутентификацию (MFA) с использованием одноразовых паролей на основе времени (TOTP).

Firebase Authentication with Identity Platform позволяет использовать TOTP в качестве дополнительного фактора для многофакторной аутентификации (MFA). При включении этой функции пользователи, пытающиеся войти в ваше приложение, видят запрос на ввод TOTP. Для его генерации им необходимо использовать приложение-аутентификатор, способное генерировать действительные TOTP-коды, например, Google Authenticator .

Прежде чем начать

  1. Включите хотя бы одного поставщика услуг, поддерживающего многофакторную аутентификацию (MFA). Обратите внимание, что все поставщики услуг, кроме следующих, поддерживают MFA:

    • Авторизация по телефону
    • Анонимная аутентификация
    • Пользовательские токены аутентификации
    • Apple Game Center
  2. Убедитесь, что ваше приложение проверяет адреса электронной почты пользователей. Многофакторная аутентификация (MFA) требует подтверждения адреса электронной почты. Это предотвращает регистрацию злоумышленниками в сервисе с использованием адреса электронной почты, который им не принадлежит, и последующую блокировку доступа фактического владельца этого адреса путем добавления второго фактора.

  3. Если вы еще этого не сделали, установите Firebase JavaScript SDK .

    Многофакторная аутентификация TOTP поддерживается только в модульном веб-SDK, версиях v9.19.1 и выше.

Включить многофакторную аутентификацию TOTP

Чтобы включить TOTP в качестве второго фактора аутентификации, используйте Admin SDK или вызовите REST-конечную точку конфигурации проекта.

Для использования Admin SDK выполните следующие действия:

  1. Если вы еще этого не сделали, установите Firebase Admin Node.js SDK .

    Поддержка TOTP MFA доступна только в версиях Firebase Admin Node.js SDK 11.6.0 и выше.

  2. Выполните следующие действия:

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

    Замените следующее:

    • NUM_ADJ_INTERVALS : Количество смежных временных интервалов, из которых принимаются TOTP-сообщения, от нуля до десяти. Значение по умолчанию — пять.

      Принцип работы TOTP заключается в том, что когда две стороны (доказывающая и подтверждающая) генерируют OTP в течение одного и того же временного окна (обычно 30 секунд), они генерируют один и тот же пароль. Однако, чтобы учесть расхождение во времени между сторонами и время реакции человека, можно настроить службу TOTP таким образом, чтобы она принимала TOTP и из смежных временных окон.

Для включения многофакторной аутентификации TOTP с использованием REST API выполните следующие действия:

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 : Количество временных интервалов от нуля до десяти. Значение по умолчанию — пять.

    Принцип работы TOTP заключается в том, что когда две стороны (доказывающая и подтверждающая) генерируют OTP в течение одного и того же временного окна (обычно 30 секунд), они генерируют один и тот же пароль. Однако, чтобы учесть расхождение во времени между сторонами и время реакции человека, можно настроить службу TOTP таким образом, чтобы она принимала TOTP и из смежных временных окон.

Выберите схему зачисления

Вы можете выбрать, требуется ли вашему приложению многофакторная аутентификация, а также как и когда регистрировать пользователей. К распространенным сценариям относятся следующие:

  • Включите второй фактор аутентификации пользователя в процесс регистрации. Используйте этот метод, если ваше приложение требует многофакторной аутентификации для всех пользователей.

  • Предложите возможность пропустить регистрацию и добавить второй фактор аутентификации. Если вы хотите поощрять, но не требовать многофакторную аутентификацию в своем приложении, вы можете использовать этот подход.

  • Предоставьте возможность добавления второго фактора аутентификации на странице управления учетной записью или профилем пользователя, а не на экране регистрации. Это минимизирует сложности в процессе регистрации, сохраняя при этом возможность многофакторной аутентификации для пользователей, которым важна безопасность.

  • Необходимо постепенно вводить второй фактор аутентификации при каждом желании пользователя получить доступ к функциям с повышенными требованиями к безопасности.

Зарегистрируйте пользователей в системе многофакторной аутентификации TOTP.

После включения TOTP MFA в качестве второго фактора для вашего приложения, реализуйте логику на стороне клиента для регистрации пользователей в TOTP MFA:

  1. Импортируйте необходимые классы и функции многофакторной аутентификации (MFA):

    import {
      multiFactor,
      TotpMultiFactorGenerator,
      TotpSecret,
      getAuth,
    } from "firebase/auth";
    
  2. Повторно аутентифицируйте пользователя.

  3. Сгенерируйте секретный TOTP-код для авторизованного пользователя:

    // Generate a TOTP secret.
    const multiFactorSession = await multiFactor(currentUser).getSession();
    const totpSecret = await TotpMultiFactorGenerator.generateSecret(
      multiFactorSession
    );
    
  4. Отобразите секретный ключ пользователю и предложите ему ввести его в приложение-аутентификатор.

    Во многих приложениях-аутентификаторах пользователи могут быстро добавлять новые секреты TOTP, сканируя QR-код, представляющий собой URI ключа, совместимого с Google Authenticator . Для генерации QR-кода с этой целью сгенерируйте URI с помощью generateQrCodeUrl() , а затем закодируйте его, используя любую библиотеку для создания QR-кодов. Например:

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

    Независимо от того, отображаете ли вы QR-код или нет, всегда отображайте секретный ключ, чтобы обеспечить поддержку приложений-аутентификаторов, которые не могут считывать QR-коды:

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

    После того, как пользователь добавит свой секретный ключ в приложение-аутентификатор, оно начнет генерировать TOTP-коды.

  5. Предложите пользователю ввести TOTP, отображаемый в его приложении-аутентификаторе, и использовать его для завершения регистрации многофакторной аутентификации:

    // 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);
    

Вход пользователей осуществляется с использованием двухфакторной аутентификации.

Для авторизации пользователей с использованием TOTP MFA используйте следующий код:

  1. Импортируйте необходимые классы и функции многофакторной аутентификации (MFA):

    import {
        getAuth,
        getMultiFactorResolver,
        TotpMultiFactorGenerator,
    } from "firebase/auth";
    
  2. Вызовите один из методов signInWith так же, как если бы вы не использовали многофакторную аутентификацию (например, signInWithEmailAndPassword() ). Если метод выдаст ошибку, auth/multi-factor-auth-required , запустите процесс многофакторной аутентификации вашего приложения.

    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. В процессе многофакторной аутентификации (MFA) вашего приложения пользователю сначала следует предложить выбрать второй фактор аутентификации. Список поддерживаемых вторых факторов можно получить, изучив свойство hints экземпляра MultiFactorResolver :

    const mfaResolver = getMultiFactorResolver(getAuth(), error);
    const enrolledFactors = mfaResolver.hints.map(info => info.displayName);
    
  4. Если пользователь решит использовать TOTP, предложите ему ввести TOTP, отображаемый в приложении-аутентификаторе, и использовать его для входа в систему:

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

Отказаться от участия в программе TOTP MFA

В этом разделе описывается, как обрабатывать случаи отмены пользователем участия в многофакторной аутентификации TOTP.

Если пользователь зарегистрировался для нескольких вариантов многофакторной аутентификации (МФА) и отменяет регистрацию для последнего активированного варианта, он получает сообщение auth/user-token-expired и выходит из системы. Пользователю необходимо снова войти в систему и подтвердить свои существующие учетные данные — например, адрес электронной почты и пароль.

Для отмены регистрации пользователя, обработки ошибки и запуска повторной аутентификации используйте следующий код:

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
        );
    }
}

Что дальше?