Двухфакторная проверка подлинности с помощью SMS в ASP.NET Core

Рик Андерсон и швейцарские разработчики

Предупреждение

Два приложения проверки подлинности (2FA) с использованием однократного алгоритма пароля на основе времени (TOTP) — это рекомендуемый в отрасли подход для 2FA. 2FA, использующий TOTP, предпочтителен для SMS 2FA. Дополнительные сведения см. в разделе "Включение создания QR-кода для приложений проверки подлинности TOTP" в ASP.NET Core для ASP.NET Core 2.0 и более поздних версий.

В этом руководстве показано, как настроить двухфакторную проверку подлинности (2FA) с помощью SMS. Инструкции приведены для twilio и ASPSMS, но вы можете использовать любой другой поставщик SMS. Перед началом работы с этим руководством рекомендуется завершить подтверждение учетной записи и восстановление паролей.

Просмотреть или скачать образец кода. Скачивание.

Создание проекта ASP.NET Core

Создайте новое веб-приложение Web2FA ASP.NET Core с отдельными учетными записями пользователей. Следуйте инструкциям, описанным в статье "Принудительное применение HTTPS" в ASP.NET Core , чтобы настроить и требовать HTTPS.

Создание учетной записи SMS

Создайте учетную запись SMS, например из twilio или ASPSMS. Запишите учетные данные проверки подлинности (для twilio: accountSid и authToken для ASPSMS: Userkey и Password).

Определение учетных данных поставщика SMS

Twilio:

На вкладке "Панель мониторинга" учетной записи Twilio скопируйте идентификатор безопасности учетной записи и маркер проверки подлинности.

ASPSMS:

В параметрах учетной записи перейдите в Userkey и скопируйте его вместе с паролем.

Позже мы будем хранить эти значения с помощью средства secret-manager в ключах SMSAccountIdentification и SMSAccountPassword.

Указание отправителя или источника

Twilio: на вкладке "Номера" скопируйте номер телефона Twilio.

ASPSMS: в меню "Разблокировка источников" разблокируйте один или несколько источников или выберите буквенно-цифровой источник (не поддерживается всеми сетями).

Позже мы будем хранить это значение с помощью средства secret-manager в ключе SMSAccountFrom.

Укажите учетные данные для службы SMS

Мы будем использовать шаблон параметров для доступа к учетной записи пользователя и ключевым параметрам.

  • Создайте класс, чтобы получить безопасный SMS-ключ. В этом примере SMSoptions класс создается в Services/SMSoptions.cs файле.
namespace Web2FA.Services
{
    public class SMSoptions
    {
        public string SMSAccountIdentification { get; set; }
        public string SMSAccountPassword { get; set; }
        public string SMSAccountFrom { get; set; }
    }
}

Задайте значение SMSAccountIdentificationSMSAccountPassword и SMSAccountFrom с помощью средства secret-manager. Например:

C:/Web2FA/src/WebApp1>dotnet user-secrets set SMSAccountIdentification 12345
info: Successfully saved SMSAccountIdentification = 12345 to the secret store.
  • Добавьте пакет NuGet для поставщика SMS. В консоли диспетчер пакетов (PMC) выполните следующие действия:

Twilio:

Install-Package Twilio

ASPSMS:

Install-Package ASPSMS

  • Добавьте код в Services/MessageServices.cs файл, чтобы включить SMS. Используйте Twilio или раздел ASPSMS:

Twilio:

using Microsoft.Extensions.Options;
using System.Threading.Tasks;
using Twilio;
using Twilio.Rest.Api.V2010.Account;
using Twilio.Types;

namespace Web2FA.Services
{
    // This class is used by the application to send Email and SMS
    // when you turn on two-factor authentication in ASP.NET Identity.
    // For more details see this link https://go.microsoft.com/fwlink/?LinkID=532713
    public class AuthMessageSender : IEmailSender, ISmsSender
    {
        public AuthMessageSender(IOptions<SMSoptions> optionsAccessor)
        {
            Options = optionsAccessor.Value;
        }

        public SMSoptions Options { get; }  // set only via Secret Manager

        public Task SendEmailAsync(string email, string subject, string message)
        {
            // Plug in your email service here to send an email.
            return Task.FromResult(0);
        }

        public Task SendSmsAsync(string number, string message)
        {
            // Plug in your SMS service here to send a text message.
            // Your Account SID from twilio.com/console
            var accountSid = Options.SMSAccountIdentification;
            // Your Auth Token from twilio.com/console
            var authToken = Options.SMSAccountPassword;

            TwilioClient.Init(accountSid, authToken);

            return MessageResource.CreateAsync(
              to: new PhoneNumber(number),
              from: new PhoneNumber(Options.SMSAccountFrom),
              body: message);
        }
    }
}

ASPSMS:

using Microsoft.Extensions.Options;
using System.Threading.Tasks;

namespace Web2FA.Services
{
    // This class is used by the application to send Email and SMS
    // when you turn on two-factor authentication in ASP.NET Identity.
    // For more details see this link https://go.microsoft.com/fwlink/?LinkID=532713
    public class AuthMessageSender : IEmailSender, ISmsSender
    {
        public AuthMessageSender(IOptions<SMSoptions> optionsAccessor)
        {
            Options = optionsAccessor.Value;
        }

        public SMSoptions Options { get; }  // set only via Secret Manager

        public Task SendEmailAsync(string email, string subject, string message)
        {
            // Plug in your email service here to send an email.
            return Task.FromResult(0);
        }

        public Task SendSmsAsync(string number, string message)
        {
            ASPSMS.SMS SMSSender = new ASPSMS.SMS();

            SMSSender.Userkey = Options.SMSAccountIdentification;
            SMSSender.Password = Options.SMSAccountPassword;
            SMSSender.Originator = Options.SMSAccountFrom;

            SMSSender.AddRecipient(number);
            SMSSender.MessageData = message;

            SMSSender.SendTextSMS();

            return Task.FromResult(0);
        }
    }
}

Настройка запуска для использования SMSoptions

Добавьте SMSoptions в контейнер службы в методе ConfigureServices в :Startup.cs

    // Add application services.
    services.AddTransient<IEmailSender, AuthMessageSender>();
    services.AddTransient<ISmsSender, AuthMessageSender>();
    services.Configure<SMSoptions>(Configuration);
}

Включение двухфакторной проверки подлинности

Views/Manage/Index.cshtmlRazor Откройте файл представления и удалите символы комментариев (поэтому разметка не закомментирована).

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

  • Запустите приложение и зарегистрируйте нового пользователя

Web application Register view open in Microsoft Edge

  • Коснитесь имени пользователя, которое активирует Index метод действия в контроллере управления. Затем коснитесь ссылки "Добавить номер телефона".

Manage view - tap the

  • Добавьте номер телефона, который получит код проверки и нажмите кнопку "Отправить код проверки".

Add Phone Number page

  • Вы получите текстовое сообщение с кодом проверки. Введите его и нажмите кнопку "Отправить"

Verify Phone Number page

Если вы не получаете текстовое сообщение, см. страницу журнала twilio.

  • В представлении "Управление" отображается успешно добавлен номер телефона.

Manage view - phone number added successfully

  • Нажмите кнопку "Включить ", чтобы включить двухфакторную проверку подлинности.

Manage view - enable two-factor authentication

Проверка двухфакторной проверки подлинности

  • Выйдите из системы.

  • Войдите в систему.

  • Учетная запись пользователя включила двухфакторную проверку подлинности, поэтому необходимо предоставить второй фактор проверки подлинности. В этом руководстве вы включили проверку телефона. Встроенные шаблоны также позволяют настроить электронную почту в качестве второго фактора. Можно настроить дополнительные дополнительные факторы проверки подлинности, такие как QR-коды. Нажмите кнопку "Отправить".

Send Verification Code view

  • Введите код, который вы получаете в SMS-сообщении.

  • Щелкнув "Запомнить этот браузер" проверка box, вы не сможете использовать 2FA для входа при использовании того же устройства и браузера. Включение 2FA и нажатие кнопки "Запомнить этот браузер " обеспечит надежную защиту 2FA от злоумышленников, пытающихся получить доступ к вашей учетной записи, если у них нет доступа к устройству. Это можно сделать на любом частном устройстве, которое вы регулярно используете. Задав этот браузер, вы получаете добавленную безопасность 2FA с устройств, которые вы не используете регулярно, и вы получаете удобство, не выполняя 2FA на собственных устройствах.

Verify view

Блокировка учетной записи для защиты от атак подбора

Блокировка учетной записи рекомендуется использовать с 2FA. После входа пользователя с помощью локальной учетной записи или учетной записи социальной сети каждая неудачная попытка 2FA сохраняется. Если достигнуто максимальное количество неудачных попыток доступа, пользователь заблокирован (по умолчанию: 5 минут блокировки после 5 неудачных попыток доступа). Успешная проверка подлинности сбрасывает количество неудачных попыток доступа и сбрасывает часы. Максимальное количество неудачных попыток доступа и время блокировки можно задать с помощью MaxFailedAccessAttempts и DefaultLockoutTimeSpan. Следующие параметры настраивают блокировку учетной записи в течение 10 минут после 10 неудачных попыток доступа:

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    services.AddMvc();

    services.Configure<IdentityOptions>(options =>
    {
        options.Lockout.MaxFailedAccessAttempts = 10;
        options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(10);
    });

    // Add application services.
    services.AddTransient<IEmailSender, AuthMessageSender>();
    services.AddTransient<ISmsSender, AuthMessageSender>();
    services.Configure<SMSoptions>(Configuration);
}

Убедитесь, что PasswordSignInAsync задано значение lockoutOnFailure true:

var result = await _signInManager.PasswordSignInAsync(
                 Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: true);