Autenticação de dois fatores com SMS no ASP.NET Core

Por Rick Anderson e Swiss-Devs

Aviso

Os aplicativos autenticadores da autenticação de dois fatores (2FA), utilizando um Algoritmo de Senha Única Baseada em Tempo (TOTP), são a abordagem recomendada pelo setor para a 2FA. A 2FA utilizando TOTP é preferível à 2FA por SMS. Para obter mais informações, confira Habilitar a geração de código QR para aplicativos autenticadores TOTP no ASP.NET Core para ASP.NET Core 2.0 e posterior.

Este tutorial mostra como você pode configurar a autenticação de dois fatores (2FA) utilizando SMS. As instruções são fornecidas para Twilio e ASPSMS, mas você pode utilizar qualquer outro provedor de SMS. Recomendamos que você conclua a seção Confirmação da conta e recuperação de senha antes de iniciar este tutorial.

Exibir ou baixar o código de exemplo. Como fazer download.

Criar um projeto ASP.NET Core

Crie um aplicativo Web ASP.NET Core chamado Web2FA com contas de usuário individuais. Siga as instruções em Forçar HTTPS no ASP.NET Core para configurar e exigir HTTPS.

Crie uma conta de SMS

Crie uma conta de SMS, por exemplo, no Twilio ou ASPSMS. Registre as credenciais de autenticação (para Twilio: accountSid e authToken, para ASPSMS: Userkey e Senha).

Como descobrir as credenciais do provedor de SMS

Twilio:

Na guia Painel da sua conta do Twilio, copie a SID da Conta e o Token de Autenticação.

ASPSMS:

Nas configurações da sua conta, navegue até Userkey e copie-a junto com sua Senha.

Posteriormente, armazenaremos esses valores com a ferramenta gerenciadora de segredos nas chaves SMSAccountIdentification e SMSAccountPassword.

Especificação da SenderID / Originador

Twilio: na guia Números, copie seu número de telefone do Twilio.

ASPSMS: no menu Desbloquear Originadores, desbloqueie um ou mais Originadores ou escolha um Originador alfanumérico (Não é suportado por todas as redes).

Posteriormente, armazenaremos esse valor com a ferramenta gerenciadora de segredos na chave SMSAccountFrom.

Forneça as credenciais para o serviço de SMS

Utilizaremos o padrão Opções para acessar as configurações da conta de usuário e da chave.

  • Crie uma classe para buscar a chave segura de SMS. Para este exemplo, a classe SMSoptions é criada no arquivo Services/SMSoptions.cs.
namespace Web2FA.Services
{
    public class SMSoptions
    {
        public string SMSAccountIdentification { get; set; }
        public string SMSAccountPassword { get; set; }
        public string SMSAccountFrom { get; set; }
    }
}

Defina SMSAccountIdentification, SMSAccountPassword e SMSAccountFrom com a ferramenta gerenciadora de segredos. Por exemplo:

C:/Web2FA/src/WebApp1>dotnet user-secrets set SMSAccountIdentification 12345
info: Successfully saved SMSAccountIdentification = 12345 to the secret store.
  • Adicione o pacote NuGet para o provedor de SMS. No Console do Gerenciador de Pacotes (PMC), execute:

Twilio:

Install-Package Twilio

ASPSMS:

Install-Package ASPSMS

  • Adicione o código no arquivo Services/MessageServices.cs para habilitar o SMS. Utilize a seção Twilio ou 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);
        }
    }
}

Configure a inicialização para que você utilize SMSoptions

Adicione SMSoptions ao contêiner de serviço no método ConfigureServices no Startup.cs:

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

Habilitar a autenticação de dois fatores

Abra o arquivo de exibição Views/Manage/Index.cshtmlRazor e remova os caracteres de comentário (para que nenhuma marcação seja comentada).

Faça o logon com a autenticação de dois fatores

  • Execute o aplicativo e registre um novo usuário

Web application Register view open in Microsoft Edge

  • Toque no seu nome de usuário, o que ativa o método de ação Index no Controlador de gerenciamento. Em seguida, toque no link Adicionar número de telefone.

Manage view - tap the

  • Adicione o número de telefone que receberá o código de verificação e toque em Enviar código de verificação.

Add Phone Number page

  • Você receberá uma mensagem de texto com o código de verificação. Insira-o e toque em Enviar

Verify Phone Number page

Se você não receber uma mensagem de texto, confira a página de registro do Twilio.

  • o modo de exibição de gerenciamento mostra que seu número de telefone foi adicionado com êxito.

Manage view - phone number added successfully

  • Toque em Habilitar para habilitar a autenticação de dois fatores.

Manage view - enable two-factor authentication

Teste a autenticação de dois fatores

  • Dê logoff.

  • Fazer logon.

  • A conta de usuário habilitou a autenticação de dois fatores, portanto, você precisa fornecer o segundo fator de autenticação. Neste tutorial, você habilitou a verificação por telefone. Os modelos internos também permitem que você configure o email como o segundo fator. Você pode configurar outros fatores secundários para autenticação, como códigos QR. Toque em Enviar.

Send Verification Code view

  • Insira o código que você recebeu na mensagem SMS.

  • Clicando na caixa de seleção Lembrar esse navegador, você não precisará usar a 2FA para fazer o logon quando utilizar o mesmo dispositivo e navegador. Ao habilitar a 2FA e clicar em Habilitar esse navegador, você terá uma forte proteção 2FA contra usuários mal-intencionados que tentem acessar a sua conta, desde que eles não tenham acesso ao seu dispositivo. Você pode fazer isso em qualquer dispositivo privado que utilize regularmente. Ao definir Lembrar esse navegador, você terá a segurança adicional da 2FA nos dispositivos que não utiliza regularmente e tem a conveniência de não precisar passar pela 2FA nos seus próprios dispositivos.

Verify view

Bloqueio da conta para proteção contra ataques de força bruta

O bloqueio da conta é recomendado com a 2FA. Quando um usuário entra por meio de uma conta local ou de uma conta social, cada tentativa fracassada da 2FA é armazenada. Se o número máximo de tentativas de acesso com falha for atingido, o usuário será bloqueado (padrão: bloqueio de 5 minutos após 5 tentativas de acesso com falha). Uma autenticação bem-sucedida zera a contagem de tentativas de acesso com falha e reinicia o relógio. O máximo de tentativas de acesso com falha e o tempo de bloqueio podem ser definidos com MaxFailedAccessAttempts e DefaultLockoutTimeSpan. A seguir, você configura o bloqueio da conta para 10 minutos após 10 tentativas de acesso com falha:

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

Confirme que PasswordSignInAsync define lockoutOnFailure para true:

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