ASP.NET Core에서 SMS를 사용하는 2단계 인증

작성자: Rick AndersonSwiss-Devs

경고

TOTP(시간 기반 일회용 암호 알고리즘)를 사용하는 2FA(2단계 인증) 인증자 앱은 2FA에 대해 업계에서 권장되는 방법입니다. TOTP를 사용하는 2FA는 SMS 2FA를 선호합니다. 자세한 내용은 ASP.NET Core 2.0 이상에 대해 ASP.NET Core에서 TOTP 인증자 앱에 QR Code 생성 사용을 참조하세요.

이 자습서에서는 SMS를 사용하여 2FA(2단계 인증)를 설정하는 방법을 보여 줍니다. twilioASPSMS에 대한 지침이 제공되지만 다른 SMS 공급자를 사용할 수 있습니다. 이 자습서를 시작하기 전에 계정 확인 및 암호 복구를 완료하는 것이 좋습니다.

샘플 코드 보기 또는 다운로드 다운로드하는 방법

새 ASP.NET Core 프로젝트 만들기

개별 사용자 계정으로 Web2FA라는 새 ASP.NET Core 웹앱을 만듭니다. ASP.NET Core HTTPS 적용의 지침에 따라 HTTPS를 설정하고 요구합니다.

SMS 계정 만들기

예를 들어 twilio 또는 ASPSMS에서 SMS 계정을 만듭니다. 인증 자격 증명(twilio: accountSid 및 authToken, ASPSMS: Userkey 및 Password)을 기록합니다.

SMS 공급자 자격 증명 구성

Twilio:

Twilio 계정의 대시보드 탭에서 계정 SID인증 토큰을 복사합니다.

ASPSMS:

계정 설정에서 Userkey로 이동하여 암호와 함께 복사합니다.

나중에 키 SMSAccountIdentificationSMSAccountPassword 내의 비밀 관리자 도구를 사용하여 이러한 값을 저장합니다.

SenderID/Originator 지정

Twilio: 숫자 탭에서 Twilio 전화 번호를 복사합니다.

ASPSMS: 발신자 잠금 해제 메뉴 내에서 하나 이상의 발신자 잠금을 해제하거나 영숫자 발신자(모든 네트워크에서 지원되지 않음)를 선택합니다.

나중에 키 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; }
    }
}

비밀 관리자 도구를 사용하여 SMSAccountIdentification, SMSAccountPasswordSMSAccountFrom을 설정합니다. 예를 들어:

C:/Web2FA/src/WebApp1>dotnet user-secrets set SMSAccountIdentification 12345
info: Successfully saved SMSAccountIdentification = 12345 to the secret store.
  • SMS 공급자에 대한 NuGet 패키지를 추가합니다. 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를 사용하도록 시작 구성

다음의 메서드에서 ConfigureServices 서비스 컨테이너에 추가 SMSoptions 합니다.Startup.cs

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

2단계 인증 사용

Views/Manage/Index.cshtmlRazor 보기 파일을 열고 메모 문자를 제거합니다(태그가 주석 처리되지 않음).

2단계 인증을 사용하여 로그인

  • 앱 실행 및 새 사용자 등록

Microsoft Edge에서 열린 웹 애플리케이션 등록 보기

  • 컨트롤러 관리에서 Index 작업 메서드를 활성화하는 사용자 이름을 탭합니다. 그런 다음, 전화 번호 추가 링크를 탭합니다.

관리 보기 -

  • 확인 코드를 받을 전화 번호를 추가하고 확인 코드 보내기를 탭합니다.

전화 번호 추가 페이지

  • 확인 코드가 있는 문자 메시지가 표시됩니다. 입력 및 제출

전화 번화 확인 페이지

문자 메시지가 표시되지 않으면 twilio 로그 페이지를 참조하세요.

  • 관리 보기는 전화 번호가 성공적으로 추가된 것을 보여 줍니다.

관리 보기 - 전화 번호가 성공적으로 추가되었습니다.

  • 사용을 탭하여 2단계 인증을 사용합니다.

관리 보기 - 2단계 인증 사용

2단계 인증 테스트

  • 로그오프합니다.

  • 로그인합니다.

  • 사용자 계정이 2단계 인증을 사용하도록 설정했으므로 두 번째 인증 요소를 제공해야 합니다. 이 자습서에서는 전화 확인을 사용하도록 설정했습니다. 기본 제공 템플릿을 사용하면 이메일을 두 번째 요소로 설정할 수도 있습니다. QR 코드와 같은 인증에 대한 두 번째 추가 요소를 설정할 수 있습니다. 제출을 탭합니다.

확인 코드 전송 보기

  • SMS 메시지에 받은 코드를 입력합니다.

  • 이 브라우저 기억 확인란을 클릭하면 동일한 디바이스 및 브라우저를 사용할 때 2FA를 사용하여 로그온할 필요가 없습니다. 2FA를 사용하도록 설정하고 이 브라우저 기억을 클릭하면 디바이스에 액세스할 수 없는 한 계정에 액세스하려는 악의적인 사용자로부터 강력한 2FA 보호를 제공합니다. 정기적으로 사용하는 모든 프라이빗 디바이스에서 이 작업을 수행할 수 있습니다. 이 브라우저를 기억하도록 설정하면 정기적으로 사용하지 않는 디바이스에서 2FA의 보안이 강화되고, 자체 디바이스에서 2FA를 통과하지 않아도 편리하게 사용할 수 있습니다.

확인 보기

무차별 암호 대입 공격으로부터 보호하기 위한 계정 잠금

2FA를 통해 계정 잠금을 권장합니다. 사용자가 로컬 계정 또는 소셜 계정을 통해 로그인하면 2FA에서 실패한 각 시도가 저장됩니다. 실패한 최대 액세스 시도 수에 도달하면 사용자가 잠깁니다(기본값: 액세스 시도 5회 실패 후 5분 잠금). 성공적인 인증은 실패한 액세스 시도 횟수를 다시 설정하고 시계를 다시 설정합니다. 최대 실패한 액세스 시도 및 잠금 시간을 사용하여 설정할 MaxFailedAccessAttemptsDefaultLockoutTimeSpan수 있습니다. 다음에서는 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);