Autenticación en dos fases con SMS en ASP.NET Core

Por Rick Anderson y Swiss-Devs

Advertencia

Las aplicaciones autenticadoras de autenticación en dos fases (2FA), que usan un algoritmo de contraseña única basado en tiempo (TOTP), son el enfoque recomendado por el sector para 2FA. La 2FA con TOTP se prefiere a SMS 2FA. Para obtener más información, consulte Habilitar la generación de código QR para aplicaciones de autenticación TOTP en ASP.NET Core para ASP.NET Core 2.0 y versiones posteriores.

En este tutorial se muestra cómo configurar la autenticación en dos fases (2FA) mediante SMS. Se proporcionan instrucciones para Twilio y ASPSMS, pero puede usar cualquier otro proveedor de SMS. Se recomienda completar la confirmación de la cuenta y la recuperación de contraseñas antes de comenzar este tutorial.

Vea o descargue el código de ejemplo. Método de descarga.

Crear un nuevo proyecto de ASP.NET Core

Cree una nueva aplicación web ASP.NET Core denominada Web2FA con cuentas de usuario individuales. Siga las instrucciones de Aplicar HTTPS en ASP.NET Core para configurar y requerir HTTPS.

Crear una cuenta de SMS

Cree una cuenta de SMS, por ejemplo, desde Twilio o ASPSMS. Registre las credenciales de autenticación (para Twilio: Sid de cuenta y token de autenticación, para ASPSMS: Clave de usuario y Contraseña).

Averiguar las credenciales del proveedor de SMS

Twilio:

En la pestaña Panel de la cuenta de Twilio, copie el SID de cuenta y el token de autenticación.

ASPSMS:

En la configuración de la cuenta, vaya a Clave de usuario y cópiela junto con la contraseña.

Más adelante almacenaremos estos valores con la herramienta Administrador de secretos dentro de las claves SMSAccountIdentification y SMSAccountPassword.

Especificación de ID del emisor/Originador

Twilio: En la pestaña Números, copie su número de teléfono de Twilio.

ASPSMS: En el menú Desbloquear originadores, desbloquee uno o varios originadores o elija un originador alfanumérico (no es compatible con todas las redes).

Más adelante almacenaremos este valor con la herramienta Administrador de secretos dentro de la clave SMSAccountFrom.

Proporcionar credenciales para el servicio SMS

Usaremos el Patrón opciones para acceder a la cuenta de usuario y la configuración de clave.

  • Cree una clase para capturar la clave SMS segura. Para este ejemplo, la clase SMSoptions se crea en el archivoServices/SMSoptions.cs.
namespace Web2FA.Services
{
    public class SMSoptions
    {
        public string SMSAccountIdentification { get; set; }
        public string SMSAccountPassword { get; set; }
        public string SMSAccountFrom { get; set; }
    }
}

Establezca SMSAccountIdentification, SMSAccountPassword y SMSAccountFrom con la herramienta Administrador de secretos. Por ejemplo:

C:/Web2FA/src/WebApp1>dotnet user-secrets set SMSAccountIdentification 12345
info: Successfully saved SMSAccountIdentification = 12345 to the secret store.
  • Agregue el paquete NuGet para el proveedor de SMS. Desde la consola del Administrador de paquetes (PMC) ejecute:

Twilio:

Install-Package Twilio

ASPSMS:

Install-Package ASPSMS

  • Agregue código en el archivo Services/MessageServices.cs para habilitar SMS. Use Twilio o la sección 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);
        }
    }
}

Configurar las tareas de inicio para utilizar SMSoptions

Agregue SMSoptions al contenedor de servicios en el método ConfigureServices en Startup.cs:

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

Habilitación de la autenticación en dos fases

Abra el archivo de vista Views/Manage/Index.cshtmlRazor y quite los caracteres de comentario (para que no se comente ningún marcado).

Iniciar sesión con autenticación en dos fases

  • Ejecute la aplicación y registre un usuario nuevo

Web application Register view open in Microsoft Edge

  • Pulse en el nombre de usuario, que activa el métodoIndex de acción en Administrar controlador. A continuación, pulse el vínculo Agregar número de teléfono.

Manage view - tap the

  • Agregue un número de teléfono que recibirá el código de verificación y pulse Enviar código de verificación.

Add Phone Number page

  • Recibirá un mensaje de texto con el código de verificación. Introdúzcalo y pulse Enviar

Verify Phone Number page

Si no recibe un mensaje de texto, consulte la página de registro de Twilio.

  • La vista Administrar muestra que el número de teléfono se agregó correctamente.

Manage view - phone number added successfully

  • Pulse Habilitar para habilitar la autenticación en dos fases.

Manage view - enable two-factor authentication

Probar la autenticación en dos fases

  • Cierre la sesión.

  • Inicie sesión.

  • La cuenta de usuario ha habilitado la autenticación en dos fases, por lo que debe proporcionar el segundo factor de autenticación. En este tutorial ha habilitado la comprobación del teléfono. Las plantillas integradas también permiten configurar el correo electrónico como segundo factor. Puede configurar otros factores adicionales para la autenticación, como códigos QR. Pulse Enviar.

Send Verification Code view

  • Escriba el código que obtuvo en el mensaje SMS.

  • Al hacer clic en la casilla de comprobaciónRecordar este explorador, se le eximirá de tener que usar 2FA para iniciar sesión al usar el mismo dispositivo y explorador. Habilitar 2FA y hacer clic en Recordar este navegador le proporcionará una protección segura de 2FA frente a usuarios malintencionados que intentan acceder a su cuenta, siempre y cuando no tengan acceso al dispositivo. Puede hacerlo en cualquier dispositivo privado que use con regularidad. Al establecer Recordar este explorador, obtiene la seguridad agregada de 2FA desde los dispositivos que no usa regularmente y obtiene la comodidad de no tener que pasar por 2FA en sus propios dispositivos.

Verify view

Bloquear la cuenta para la protección contra ataques por fuerza bruta

Se recomienda el bloqueo de la cuenta con 2FA. Una vez que un usuario inicia sesión a través de una cuenta local o una cuenta social, se almacena cada intento erróneo en realizar 2FA. Si se alcanza el número máximo de intentos de acceso fallidos, el usuario se bloquea (valor predeterminado: bloqueo de 5 minutos después de 5 intentos de acceso fallidos). Una autenticación correcta restablece el recuento de intentos de accesos fallidos y restablece el reloj. El número máximo de intentos de acceso fallidos y el tiempo de bloqueo se pueden establecer con MaxFailedAccessAttempts y DefaultLockoutTimeSpan. A continuación se configura el bloqueo de la cuenta durante 10 minutos después de 10 intentos de acceso fallidos:

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 establece lockoutOnFailure entrue:

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