Aracılığıyla paylaş


ASP.NET Core'da çok faktörlü kimlik doğrulaması

Not

Bu, bu makalenin en son sürümü değildir. Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.

Uyarı

ASP.NET Core'un bu sürümü artık desteklenmiyor. Daha fazla bilgi için bkz . .NET ve .NET Core Destek İlkesi. Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.

Önemli

Bu bilgiler, ticari olarak piyasaya sürülmeden önce önemli ölçüde değiştirilebilen bir yayın öncesi ürünle ilgilidir. Burada verilen bilgilerle ilgili olarak Microsoft açık veya zımni hiçbir garanti vermez.

Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.

Tarafından Damien Bowden

Örnek kodu görüntüleme veya indirme (damienbod/AspNetCoreHybridFlowWithApi GitHub deposu)

Çok faktörlü kimlik doğrulaması (MFA), bir kullanıcının ek tanımlama biçimleri için oturum açma olayı sırasında istendiği bir işlemdir. Bu istem, bir cep telefonundan kod girmek, FIDO2 anahtarı kullanmak veya parmak izi taraması sağlamak olabilir. İkinci bir kimlik doğrulama biçimine ihtiyacınız olduğunda güvenlik iyileştirilmiştir. Ek faktör bir saldırgan tarafından kolayca elde edilemez veya çoğaltılamaz.

Bu makale aşağıdaki alanları kapsar:

  • MFA nedir ve hangi MFA akışları önerilir?
  • ASP.NET Core kullanarak yönetim sayfaları için MFA'yi yapılandırma Identity
  • OpenID Connect sunucusuna MFA oturum açma gereksinimi gönderme
  • ASP.NET Core OpenID Connect istemcisini MFA gerektirmeye zorlama

MFA, 2FA

MFA, bildiğiniz, sahip olduğunuz bir şey veya kullanıcının kimlik doğrulaması için biyometrik doğrulama gibi bir kimlik için en az iki veya daha fazla türde kanıt gerektirir.

İki öğeli kimlik doğrulaması (2FA), MFA'nın bir alt kümesi gibidir, ancak MFA'nın kimliği kanıtlamak için iki veya daha fazla faktör gerektirmesi farktır.

2FA, ASP.NET Core Identitykullanılırken varsayılan olarak desteklenir. Belirli bir kullanıcı için 2FA'yı etkinleştirmek veya devre dışı bırakmak için özelliğini ayarlayın IdentityUser<TKey>.TwoFactorEnabled . ASP.NET Temel Identity Varsayılan kullanıcı arabirimi, 2FA'nın yapılandırılması için sayfalar içerir.

MFA TOTP (Zamana Dayalı Tek Seferlik Parola Algoritması)

TOTP kullanan MFA, ASP.NET Core Identitykullanılırken varsayılan olarak desteklenir. Bu yaklaşım, aşağıdakiler dahil olmak üzere tüm uyumlu kimlik doğrulayıcı uygulamalarıyla birlikte kullanılabilir:

  • Microsoft Authenticator
  • Google Authenticator

Uygulama ayrıntıları için bkz . ASP.NET Core'da TOTP kimlik doğrulayıcı uygulamaları için QR Kodu oluşturmayı etkinleştirme.

MFA TOTP desteğini devre dışı bırakmak için yerine kullanarak AddIdentity kimlik doğrulamasını AddDefaultIdentityyapılandırın. AddDefaultIdentity , MFA TOTP için bir tane de dahil olmak üzere birden çok belirteç sağlayıcısını kaydeden dahili olarak çağırır AddDefaultTokenProviders . Yalnızca belirli belirteç sağlayıcılarını kaydetmek için her gerekli sağlayıcıyı çağırın AddTokenProvider . Kullanılabilir belirteç sağlayıcıları hakkında daha fazla bilgi için GitHub'daki AddDefaultTokenProviders kaynağına bakın.

MFA geçiş anahtarları/FIDO2 veya parolasız

passkeys/FIDO2 şu anda:

  • MFA'ya ulaşmanın en güvenli yolu.
  • Kimlik avı saldırılarına karşı koruma sağlayan MFA. (Sertifika kimlik doğrulaması ve İş için Windows'un yanı sıra)

Şu anda ASP.NET Core doğrudan geçiş anahtarlarını/FIDO2'yi desteklememektedir. Geçiş anahtarları/FIDO2, MFA veya parolasız akışlar için kullanılabilir.

Microsoft Entra ID, geçiş anahtarları/FIDO2 ve parolasız akışlar için destek sağlar. Daha fazla bilgi için bkz . Parolasız kimlik doğrulama seçenekleri.

Parolasız MFA'nın diğer biçimleri kimlik avına karşı koruma sağlamaz veya korumayabilir.

MFA SMS

SMS ile MFA, parola kimlik doğrulaması (tek faktör) ile karşılaştırıldığında güvenliği büyük ölçüde artırır. Ancak SMS'in ikinci bir faktör olarak kullanılması artık önerilmez. Bu tür bir uygulama için çok fazla bilinen saldırı vektörleri var.

NIST yönergeleri

ASP.NET Core kullanarak yönetim sayfaları için MFA'yi yapılandırma Identity

MFA, kullanıcılara ASP.NET Core Identity uygulamasındaki hassas sayfalara erişmeye zorlanabilir. Bu, farklı kimlikler için farklı erişim düzeylerinin bulunduğu uygulamalar için yararlı olabilir. Örneğin, kullanıcılar profil verilerini parolayla oturum açma bilgilerini kullanarak görüntüleyebilir, ancak yöneticinin yönetim sayfalarına erişmek için MFA kullanması gerekebilir.

MFA talebiyle oturum açmayı genişletme

Tanıtım kodu ve Razor Sayfaları ile Identity ASP.NET Core kullanılarak ayarlanır. AddIdentity yöntemi yerine kullanılırAddDefaultIdentity, bu nedenle başarılı bir oturum açma sonrasında kimliğe talep eklemek için bir IUserClaimsPrincipalFactory uygulama kullanılabilir.

builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlite(
        Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddIdentity<IdentityUser, IdentityRole>(options =>
		options.SignIn.RequireConfirmedAccount = false)
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

builder.Services.AddSingleton<IEmailSender, EmailSender>();
builder.Services.AddScoped<IUserClaimsPrincipalFactory<IdentityUser>, 
    AdditionalUserClaimsPrincipalFactory>();

builder.Services.AddAuthorization(options =>
    options.AddPolicy("TwoFactorEnabled", x => x.RequireClaim("amr", "mfa")));

builder.Services.AddRazorPages();

sınıfı, AdditionalUserClaimsPrincipalFactory talebi yalnızca başarılı bir oturum açma sonrasında kullanıcı taleplerine ekler amr . Talebin değeri veritabanından okunur. Talep buraya eklenir çünkü kullanıcının yalnızca kimlik MFA ile oturum açmışsa daha yüksek korumalı görünüme erişmesi gerekir. Veritabanı görünümü talebi kullanmak yerine doğrudan veritabanından okunursa, MFA etkinleştirildikten sonra doğrudan MFA olmadan görünüme erişmek mümkündür.

using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;

namespace IdentityStandaloneMfa
{
    public class AdditionalUserClaimsPrincipalFactory : 
        UserClaimsPrincipalFactory<IdentityUser, IdentityRole>
    {
        public AdditionalUserClaimsPrincipalFactory( 
            UserManager<IdentityUser> userManager,
            RoleManager<IdentityRole> roleManager, 
            IOptions<IdentityOptions> optionsAccessor) 
            : base(userManager, roleManager, optionsAccessor)
        {
        }

        public async override Task<ClaimsPrincipal> CreateAsync(IdentityUser user)
        {
            var principal = await base.CreateAsync(user);
            var identity = (ClaimsIdentity)principal.Identity;

            var claims = new List<Claim>();

            if (user.TwoFactorEnabled)
            {
                claims.Add(new Claim("amr", "mfa"));
            }
            else
            {
                claims.Add(new Claim("amr", "pwd"));
            }

            identity.AddClaims(claims);
            return principal;
        }
    }
}

Identity Hizmet kurulumu sınıfında değiştiğindenStartup, düzenlerinin Identity güncelleştirilmiş olması gerekir. Identity Sayfaları uygulamaya iskelesi oluşturun. Dosyadaki Identity/Account/Manage/_Layout.cshtml düzeni tanımlayın.

@{
    Layout = "/Pages/Shared/_Layout.cshtml";
}

Ayrıca, sayfalardan tüm yönetme sayfaları için düzeni atayın Identity :

@{
    Layout = "_Layout.cshtml";
}

Yönetim sayfasında MFA gereksinimini doğrulama

Yönetim Razor Sayfası, kullanıcının MFA kullanarak oturum açtığını doğrular. yönteminde OnGet kimlik, kullanıcı taleplerine erişmek için kullanılır. Talep amr değeri mfaiçin denetlendi. Kimlikte bu talep yoksa veya ise false, sayfa MFA'yı Etkinleştir sayfasına yönlendirilir. Kullanıcı MFA olmadan zaten oturum açtığından bu mümkündür.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace IdentityStandaloneMfa
{
    public class AdminModel : PageModel
    {
        public IActionResult OnGet()
        {
            var claimTwoFactorEnabled = 
                User.Claims.FirstOrDefault(t => t.Type == "amr");

            if (claimTwoFactorEnabled != null && 
                "mfa".Equals(claimTwoFactorEnabled.Value))
            {
                // You logged in with MFA, do the administrative stuff
            }
            else
            {
                return Redirect(
                    "/Identity/Account/Manage/TwoFactorAuthentication");
            }

            return Page();
        }
    }
}

Kullanıcı oturum açma bilgilerini değiştirmek için kullanıcı arabirimi mantığı

Başlangıçta bir yetkilendirme ilkesi eklendi. İlke, değerine mfasahip talebi gerektiriramr.

services.AddAuthorization(options =>
    options.AddPolicy("TwoFactorEnabled",
        x => x.RequireClaim("amr", "mfa")));

Bu ilke daha sonra görünümde _Layout yönetici menüsünü şu uyarıyla göstermek veya gizlemek için kullanılabilir:

@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@inject IAuthorizationService AuthorizationService

Kimlik MFA kullanarak oturum açtıysa, Yönetici menüsü araç ipucu uyarısı olmadan görüntülenir. Kullanıcı MFA olmadan oturum açtığında, kullanıcıyı bilgilendiren araç ipucuyla birlikte Yönetici (Etkin Değil) menüsü görüntülenir (uyarı açıklanmaktadır).

@if (SignInManager.IsSignedIn(User))
{
    @if ((AuthorizationService.AuthorizeAsync(User, "TwoFactorEnabled")).Result.Succeeded)
    {
        <li class="nav-item">
            <a class="nav-link text-dark" asp-area="" asp-page="/Admin">Admin</a>
        </li>
    }
    else
    {
        <li class="nav-item">
            <a class="nav-link text-dark" asp-area="" asp-page="/Admin" 
               id="tooltip-demo"  
               data-toggle="tooltip" 
               data-placement="bottom" 
               title="MFA is NOT enabled. This is required for the Admin Page. If you have activated MFA, then logout, login again.">
                Admin (Not Enabled)
            </a>
        </li>
    }
}

Kullanıcı MFA olmadan oturum açarsa uyarı görüntülenir:

Yönetici MFA kimlik doğrulaması

Kullanıcı, Yönetici bağlantısına tıklandığında MFA etkinleştirme görünümüne yönlendirilir:

Yönetici MFA kimlik doğrulamayı etkinleştirir

OpenID Connect sunucusuna MFA oturum açma gereksinimi gönderme

parametresi, acr_values bir kimlik doğrulama isteğinde mfa istemciden sunucuya gerekli değeri geçirmek için kullanılabilir.

Not

Bunun acr_values çalışması için parametresinin OpenID Connect sunucusunda işlenmesi gerekir.

OpenID Connect ASP.NET Core istemcisi

ASP.NET Core Razor Pages OpenID Connect istemci uygulaması, OpenID Connect sunucusunda oturum açmak için yöntemini kullanır AddOpenIdConnect . acr_values parametresi değeriyle mfa ayarlanır ve kimlik doğrulama isteğiyle gönderilir. OpenIdConnectEvents bunu eklemek için kullanılır.

Önerilen acr_values parametre değerleri için bkz . Kimlik Doğrulama Yöntemi Başvuru Değerleri.

build.Services.AddAuthentication(options =>
{
	options.DefaultScheme =
		CookieAuthenticationDefaults.AuthenticationScheme;
	options.DefaultChallengeScheme =
		OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
	options.SignInScheme =
		CookieAuthenticationDefaults.AuthenticationScheme;
	options.Authority = "<OpenID Connect server URL>";
	options.RequireHttpsMetadata = true;
	options.ClientId = "<OpenID Connect client ID>";
	options.ClientSecret = "<>";
	options.ResponseType = "code";
	options.UsePkce = true;	
	options.Scope.Add("profile");
	options.Scope.Add("offline_access");
	options.SaveTokens = true;
	options.AdditionalAuthorizationParameters.Add("acr_values", "mfa");
});

ASP.NET Core ile OpenID Connect Duende IdentityServer sunucusu örneği Identity

Pages ile Razor ASP.NET Core Identity kullanılarak uygulanan OpenID Connect sunucusunda adlı ErrorEnable2FA.cshtml yeni bir sayfa oluşturulur. Görünüm:

  • , Identity MFA gerektiren ancak kullanıcı tarafından içinde Identityetkinleştirilmemiş bir uygulamadan geliyorsa görüntülenir.
  • Kullanıcıyı bilgilendirip bunu etkinleştirmek için bir bağlantı ekler.
@{
    ViewData["Title"] = "ErrorEnable2FA";
}

<h1>The client application requires you to have MFA enabled. Enable this, try login again.</h1>

<br />

You can enable MFA to login here:

<br />

<a href="~/Identity/Account/Manage/TwoFactorAuthentication">Enable MFA</a>

yönteminde LoginIIdentityServerInteractionService , arabirim uygulaması _interaction OpenID Connect istek parametrelerine erişmek için kullanılır. acr_values parametresine AcrValues özelliği kullanılarak erişilir. İstemci bunu set ile mfa gönderdiğinde, bu daha sonra denetlenebilir.

MFA gerekliyse ve ASP.NET Core'daki Identity kullanıcı MFA'yı etkinleştirdiyse oturum açma işlemi devam eder. Kullanıcının MFA'sı etkin olmadığında, kullanıcı özel görünümüne ErrorEnable2FA.cshtmlyönlendirilir. Ardından ASP.NET Core Identity kullanıcının oturumunu açar.

Fido2Store, kullanıcının özel bir FIDO2 Belirteç Sağlayıcısı kullanarak MFA'yi etkinleştirip etkinleştirmediğini denetlemek için kullanılır.

public async Task<IActionResult> OnPost()
{
	// check if we are in the context of an authorization request
	var context = await _interaction.GetAuthorizationContextAsync(Input.ReturnUrl);

	var requires2Fa = context?.AcrValues.Count(t => t.Contains("mfa")) >= 1;

	var user = await _userManager.FindByNameAsync(Input.Username);
	if (user != null && !user.TwoFactorEnabled && requires2Fa)
	{
		return RedirectToPage("/Home/ErrorEnable2FA/Index");
	}

	// code omitted for brevity

	if (ModelState.IsValid)
	{
		var result = await _signInManager.PasswordSignInAsync(Input.Username, Input.Password, Input.RememberLogin, lockoutOnFailure: true);
		if (result.Succeeded)
		{
			// code omitted for brevity
		}
		if (result.RequiresTwoFactor)
		{
			var fido2ItemExistsForUser = await _fido2Store.GetCredentialsByUserNameAsync(user.UserName);
			if (fido2ItemExistsForUser.Count > 0)
			{
				return RedirectToPage("/Account/LoginFido2Mfa", new { area = "Identity", Input.ReturnUrl, Input.RememberLogin });
			}

			return RedirectToPage("/Account/LoginWith2fa", new { area = "Identity", Input.ReturnUrl, RememberMe = Input.RememberLogin });
		}

		await _events.RaiseAsync(new UserLoginFailureEvent(Input.Username, "invalid credentials", clientId: context?.Client.ClientId));
		ModelState.AddModelError(string.Empty, LoginOptions.InvalidCredentialsErrorMessage);
	}

	// something went wrong, show form with error
	await BuildModelAsync(Input.ReturnUrl);
	return Page();
}

Kullanıcı zaten oturum açmışsa istemci uygulaması:

  • Yine de talebi doğrular amr .
  • MFA'yı ASP.NET Çekirdek Identity görünümüne bir bağlantıyla ayarlayabilir.

acr_values-1 resmi

ASP.NET Core OpenID Connect istemcisini MFA gerektirmeye zorlama

Bu örnekte, oturum açmak için OpenID Connect kullanan bir ASP.NET Temel Razor Sayfa uygulamasının kullanıcıların MFA kullanarak kimlik doğrulaması yapılmasını nasıl gerektirebileceği gösterilmektedir.

MFA gereksinimini doğrulamak için bir IAuthorizationRequirement gereksinim oluşturulur. Bu, MFA gerektiren bir ilke kullanılarak sayfalara eklenir.

using Microsoft.AspNetCore.Authorization;

namespace AspNetCoreRequireMfaOidc;

public class RequireMfa : IAuthorizationRequirement{}

AuthorizationHandler, talebi kullanacak amr ve değerini mfadenetleyecek şekilde uygulanır. amr başarılı bir kimlik doğrulamasında id_token döndürülür ve Kimlik Doğrulama Yöntemi Başvuru Değerleri belirtiminde tanımlanan birçok farklı değere sahip olabilir.

Döndürülen değer, kimliğin kimliğinin nasıl doğrulanmış olduğuna ve OpenID Connect sunucu uygulamasına bağlıdır.

gereksinimini AuthorizationHandlerRequireMfa kullanır ve talebi doğrular amr . OpenID Connect sunucusu, ASP.NET Core Identityile Duende Identity Sunucusu kullanılarak uygulanabilir. Bir kullanıcı TOTP kullanarak oturum açtığında, amr talep bir MFA değeriyle döndürülür. Farklı bir OpenID Connect sunucu uygulaması veya farklı bir MFA türü kullanıyorsanız, amr talep farklı bir değere sahip olabilir veya olabilir. Kodun da bunu kabul etmesi için genişletilmesi gerekir.

public class RequireMfaHandler : AuthorizationHandler<RequireMfa>
{
	protected override Task HandleRequirementAsync(
		AuthorizationHandlerContext context, 
		RequireMfa requirement)
	{
		if (context == null)
			throw new ArgumentNullException(nameof(context));
		if (requirement == null)
			throw new ArgumentNullException(nameof(requirement));

		var amrClaim =
			context.User.Claims.FirstOrDefault(t => t.Type == "amr");

		if (amrClaim != null && amrClaim.Value == Amr.Mfa)
		{
			context.Succeed(requirement);
		}

		return Task.CompletedTask;
	}
}

Program dosyasında, AddOpenIdConnect yöntemi varsayılan sınama şeması olarak kullanılır. Talebi denetlemek amr için kullanılan yetkilendirme işleyicisi, Inversion of Control kapsayıcısına eklenir. Ardından gereksinimi ekleyen RequireMfa bir ilke oluşturulur.

builder.Services.ConfigureApplicationCookie(options =>
        options.Cookie.SecurePolicy =
            CookieSecurePolicy.Always);

builder.Services.AddSingleton<IAuthorizationHandler, RequireMfaHandler>();

builder.Services.AddAuthentication(options =>
{
	options.DefaultScheme =
		CookieAuthenticationDefaults.AuthenticationScheme;
	options.DefaultChallengeScheme =
		OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
	options.SignInScheme =
		CookieAuthenticationDefaults.AuthenticationScheme;
	options.Authority = "https://localhost:44352";
	options.RequireHttpsMetadata = true;
	options.ClientId = "AspNetCoreRequireMfaOidc";
	options.ClientSecret = "AspNetCoreRequireMfaOidcSecret";
	options.ResponseType = "code";
	options.UsePkce = true;	
	options.Scope.Add("profile");
	options.Scope.Add("offline_access");
	options.SaveTokens = true;
});

builder.Services.AddAuthorization(options =>
{
	options.AddPolicy("RequireMfa", policyIsAdminRequirement =>
	{
		policyIsAdminRequirement.Requirements.Add(new RequireMfa());
	});
});

builder.Services.AddRazorPages();

Bu ilke daha sonra sayfada gerektiği gibi kullanılır Razor . İlke, uygulamanın tamamı için de genel olarak eklenebilir.

[Authorize(Policy= "RequireMfa")]
public class IndexModel : PageModel
{
    public void OnGet()
    {
    }
}

Kullanıcı MFA olmadan kimlik doğrulaması yaparsa, amr talep büyük olasılıkla bir pwd değere sahip olur. İstek, sayfaya erişme yetkisine sahip olmayacaktır. Kullanıcı varsayılan değerleri kullanarak Account/AccessDenied sayfasına yönlendirilir. Bu davranış değiştirilebilir veya burada kendi özel mantığınızı uygulayabilirsiniz. Bu örnekte, geçerli kullanıcının hesabı için MFA ayarlayabilmesi için bir bağlantı eklenir.

@page
@model AspNetCoreRequireMfaOidc.AccessDeniedModel
@{
    ViewData["Title"] = "AccessDenied";
    Layout = "~/Pages/Shared/_Layout.cshtml";
}

<h1>AccessDenied</h1>

You require MFA to login here

<a href="https://localhost:44352/Manage/TwoFactorAuthentication">Enable MFA</a>

Artık sayfaya veya web sitesine yalnızca MFA ile kimlik doğrulayan kullanıcılar erişebilir. Farklı MFA türleri kullanılıyorsa veya 2FA uygunsa, amr talep farklı değerlere sahip olur ve doğru işlenmesi gerekir. Farklı OpenID Connect sunucuları da bu talep için farklı değerler döndürür ve Kimlik Doğrulama Yöntemi Başvuru Değerleri belirtimini izlemeyebilir.

MFA olmadan oturum açarken (örneğin, yalnızca bir parola kullanarak):

  • amr şu değere pwd sahiptir:

    amr pwd değerine sahiptir

  • Erişim reddedildi:

    Erişim reddedildi

Alternatif olarak, ile IdentityOTP kullanarak oturum açma:

ile OTP kullanarak oturum açma Identity

Ek kaynaklar

Tarafından Damien Bowden

Örnek kodu görüntüleme veya indirme (damienbod/AspNetCoreHybridFlowWithApi GitHub deposu)

Çok faktörlü kimlik doğrulaması (MFA), bir kullanıcının ek tanımlama biçimleri için oturum açma olayı sırasında istendiği bir işlemdir. Bu istem, bir cep telefonundan kod girmek, FIDO2 anahtarı kullanmak veya parmak izi taraması sağlamak olabilir. İkinci bir kimlik doğrulama biçimine ihtiyacınız olduğunda güvenlik iyileştirilmiştir. Ek faktör bir saldırgan tarafından kolayca elde edilemez veya çoğaltılamaz.

Bu makale aşağıdaki alanları kapsar:

  • MFA nedir ve hangi MFA akışları önerilir?
  • ASP.NET Core kullanarak yönetim sayfaları için MFA'yi yapılandırma Identity
  • OpenID Connect sunucusuna MFA oturum açma gereksinimi gönderme
  • ASP.NET Core OpenID Connect istemcisini MFA gerektirmeye zorlama

MFA, 2FA

MFA, bildiğiniz, sahip olduğunuz bir şey veya kullanıcının kimlik doğrulaması için biyometrik doğrulama gibi bir kimlik için en az iki veya daha fazla türde kanıt gerektirir.

İki öğeli kimlik doğrulaması (2FA), MFA'nın bir alt kümesi gibidir, ancak MFA'nın kimliği kanıtlamak için iki veya daha fazla faktör gerektirmesi farktır.

2FA, ASP.NET Core Identitykullanılırken varsayılan olarak desteklenir. Belirli bir kullanıcı için 2FA'yı etkinleştirmek veya devre dışı bırakmak için özelliğini ayarlayın IdentityUser<TKey>.TwoFactorEnabled . ASP.NET Temel Identity Varsayılan kullanıcı arabirimi, 2FA'nın yapılandırılması için sayfalar içerir.

MFA TOTP (Zamana Dayalı Tek Seferlik Parola Algoritması)

TOTP kullanan MFA, ASP.NET Core Identitykullanılırken varsayılan olarak desteklenir. Bu yaklaşım, aşağıdakiler dahil olmak üzere tüm uyumlu kimlik doğrulayıcı uygulamalarıyla birlikte kullanılabilir:

  • Microsoft Authenticator
  • Google Authenticator

Uygulama ayrıntıları için bkz . ASP.NET Core'da TOTP kimlik doğrulayıcı uygulamaları için QR Kodu oluşturmayı etkinleştirme.

MFA TOTP desteğini devre dışı bırakmak için yerine kullanarak AddIdentity kimlik doğrulamasını AddDefaultIdentityyapılandırın. AddDefaultIdentity , MFA TOTP için bir tane de dahil olmak üzere birden çok belirteç sağlayıcısını kaydeden dahili olarak çağırır AddDefaultTokenProviders . Yalnızca belirli belirteç sağlayıcılarını kaydetmek için her gerekli sağlayıcıyı çağırın AddTokenProvider . Kullanılabilir belirteç sağlayıcıları hakkında daha fazla bilgi için GitHub'daki AddDefaultTokenProviders kaynağına bakın.

MFA geçiş anahtarları/FIDO2 veya parolasız

passkeys/FIDO2 şu anda:

  • MFA'ya ulaşmanın en güvenli yolu.
  • Kimlik avı saldırılarına karşı koruma sağlayan MFA. (Sertifika kimlik doğrulaması ve İş için Windows'un yanı sıra)

Şu anda ASP.NET Core doğrudan geçiş anahtarlarını/FIDO2'yi desteklememektedir. Geçiş anahtarları/FIDO2, MFA veya parolasız akışlar için kullanılabilir.

Microsoft Entra ID, geçiş anahtarları/FIDO2 ve parolasız akışlar için destek sağlar. Daha fazla bilgi için bkz . Parolasız kimlik doğrulama seçenekleri.

Parolasız MFA'nın diğer biçimleri kimlik avına karşı koruma sağlamaz veya korumayabilir.

MFA SMS

SMS ile MFA, parola kimlik doğrulaması (tek faktör) ile karşılaştırıldığında güvenliği büyük ölçüde artırır. Ancak SMS'in ikinci bir faktör olarak kullanılması artık önerilmez. Bu tür bir uygulama için çok fazla bilinen saldırı vektörleri var.

NIST yönergeleri

ASP.NET Core kullanarak yönetim sayfaları için MFA'yi yapılandırma Identity

MFA, kullanıcılara ASP.NET Core Identity uygulamasındaki hassas sayfalara erişmeye zorlanabilir. Bu, farklı kimlikler için farklı erişim düzeylerinin bulunduğu uygulamalar için yararlı olabilir. Örneğin, kullanıcılar profil verilerini parolayla oturum açma bilgilerini kullanarak görüntüleyebilir, ancak yöneticinin yönetim sayfalarına erişmek için MFA kullanması gerekebilir.

MFA talebiyle oturum açmayı genişletme

Tanıtım kodu ve Razor Sayfaları ile Identity ASP.NET Core kullanılarak ayarlanır. AddIdentity yöntemi yerine kullanılırAddDefaultIdentity, bu nedenle başarılı bir oturum açma sonrasında kimliğe talep eklemek için bir IUserClaimsPrincipalFactory uygulama kullanılabilir.

builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlite(
        Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddIdentity<IdentityUser, IdentityRole>(options =>
		options.SignIn.RequireConfirmedAccount = false)
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

builder.Services.AddSingleton<IEmailSender, EmailSender>();
builder.Services.AddScoped<IUserClaimsPrincipalFactory<IdentityUser>, 
    AdditionalUserClaimsPrincipalFactory>();

builder.Services.AddAuthorization(options =>
    options.AddPolicy("TwoFactorEnabled", x => x.RequireClaim("amr", "mfa")));

builder.Services.AddRazorPages();

sınıfı, AdditionalUserClaimsPrincipalFactory talebi yalnızca başarılı bir oturum açma sonrasında kullanıcı taleplerine ekler amr . Talebin değeri veritabanından okunur. Talep buraya eklenir çünkü kullanıcının yalnızca kimlik MFA ile oturum açmışsa daha yüksek korumalı görünüme erişmesi gerekir. Veritabanı görünümü talebi kullanmak yerine doğrudan veritabanından okunursa, MFA etkinleştirildikten sonra doğrudan MFA olmadan görünüme erişmek mümkündür.

using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;

namespace IdentityStandaloneMfa
{
    public class AdditionalUserClaimsPrincipalFactory : 
        UserClaimsPrincipalFactory<IdentityUser, IdentityRole>
    {
        public AdditionalUserClaimsPrincipalFactory( 
            UserManager<IdentityUser> userManager,
            RoleManager<IdentityRole> roleManager, 
            IOptions<IdentityOptions> optionsAccessor) 
            : base(userManager, roleManager, optionsAccessor)
        {
        }

        public async override Task<ClaimsPrincipal> CreateAsync(IdentityUser user)
        {
            var principal = await base.CreateAsync(user);
            var identity = (ClaimsIdentity)principal.Identity;

            var claims = new List<Claim>();

            if (user.TwoFactorEnabled)
            {
                claims.Add(new Claim("amr", "mfa"));
            }
            else
            {
                claims.Add(new Claim("amr", "pwd"));
            }

            identity.AddClaims(claims);
            return principal;
        }
    }
}

Identity Hizmet kurulumu sınıfında değiştiğindenStartup, düzenlerinin Identity güncelleştirilmiş olması gerekir. Identity Sayfaları uygulamaya iskelesi oluşturun. Dosyadaki Identity/Account/Manage/_Layout.cshtml düzeni tanımlayın.

@{
    Layout = "/Pages/Shared/_Layout.cshtml";
}

Ayrıca, sayfalardan tüm yönetme sayfaları için düzeni atayın Identity :

@{
    Layout = "_Layout.cshtml";
}

Yönetim sayfasında MFA gereksinimini doğrulama

Yönetim Razor Sayfası, kullanıcının MFA kullanarak oturum açtığını doğrular. yönteminde OnGet kimlik, kullanıcı taleplerine erişmek için kullanılır. Talep amr değeri mfaiçin denetlendi. Kimlikte bu talep yoksa veya ise false, sayfa MFA'yı Etkinleştir sayfasına yönlendirilir. Kullanıcı MFA olmadan zaten oturum açtığından bu mümkündür.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace IdentityStandaloneMfa
{
    public class AdminModel : PageModel
    {
        public IActionResult OnGet()
        {
            var claimTwoFactorEnabled = 
                User.Claims.FirstOrDefault(t => t.Type == "amr");

            if (claimTwoFactorEnabled != null && 
                "mfa".Equals(claimTwoFactorEnabled.Value))
            {
                // You logged in with MFA, do the administrative stuff
            }
            else
            {
                return Redirect(
                    "/Identity/Account/Manage/TwoFactorAuthentication");
            }

            return Page();
        }
    }
}

Kullanıcı oturum açma bilgilerini değiştirmek için kullanıcı arabirimi mantığı

Başlangıçta bir yetkilendirme ilkesi eklendi. İlke, değerine mfasahip talebi gerektiriramr.

services.AddAuthorization(options =>
    options.AddPolicy("TwoFactorEnabled",
        x => x.RequireClaim("amr", "mfa")));

Bu ilke daha sonra görünümde _Layout yönetici menüsünü şu uyarıyla göstermek veya gizlemek için kullanılabilir:

@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@inject IAuthorizationService AuthorizationService

Kimlik MFA kullanarak oturum açtıysa, Yönetici menüsü araç ipucu uyarısı olmadan görüntülenir. Kullanıcı MFA olmadan oturum açtığında, kullanıcıyı bilgilendiren araç ipucuyla birlikte Yönetici (Etkin Değil) menüsü görüntülenir (uyarı açıklanmaktadır).

@if (SignInManager.IsSignedIn(User))
{
    @if ((AuthorizationService.AuthorizeAsync(User, "TwoFactorEnabled")).Result.Succeeded)
    {
        <li class="nav-item">
            <a class="nav-link text-dark" asp-area="" asp-page="/Admin">Admin</a>
        </li>
    }
    else
    {
        <li class="nav-item">
            <a class="nav-link text-dark" asp-area="" asp-page="/Admin" 
               id="tooltip-demo"  
               data-toggle="tooltip" 
               data-placement="bottom" 
               title="MFA is NOT enabled. This is required for the Admin Page. If you have activated MFA, then logout, login again.">
                Admin (Not Enabled)
            </a>
        </li>
    }
}

Kullanıcı MFA olmadan oturum açarsa uyarı görüntülenir:

Yönetici MFA kimlik doğrulaması

Kullanıcı, Yönetici bağlantısına tıklandığında MFA etkinleştirme görünümüne yönlendirilir:

Yönetici MFA kimlik doğrulamayı etkinleştirir

OpenID Connect sunucusuna MFA oturum açma gereksinimi gönderme

parametresi, acr_values bir kimlik doğrulama isteğinde mfa istemciden sunucuya gerekli değeri geçirmek için kullanılabilir.

Not

Bunun acr_values çalışması için parametresinin OpenID Connect sunucusunda işlenmesi gerekir.

OpenID Connect ASP.NET Core istemcisi

ASP.NET Core Razor Pages OpenID Connect istemci uygulaması, OpenID Connect sunucusunda oturum açmak için yöntemini kullanır AddOpenIdConnect . acr_values parametresi değeriyle mfa ayarlanır ve kimlik doğrulama isteğiyle gönderilir. OpenIdConnectEvents bunu eklemek için kullanılır.

Önerilen acr_values parametre değerleri için bkz . Kimlik Doğrulama Yöntemi Başvuru Değerleri.

build.Services.AddAuthentication(options =>
{
	options.DefaultScheme =
		CookieAuthenticationDefaults.AuthenticationScheme;
	options.DefaultChallengeScheme =
		OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
	options.SignInScheme =
		CookieAuthenticationDefaults.AuthenticationScheme;
	options.Authority = "<OpenID Connect server URL>";
	options.RequireHttpsMetadata = true;
	options.ClientId = "<OpenID Connect client ID>";
	options.ClientSecret = "<>";
	options.ResponseType = "code";
	options.UsePkce = true;	
	options.Scope.Add("profile");
	options.Scope.Add("offline_access");
	options.SaveTokens = true;
	options.Events = new OpenIdConnectEvents
	{
		OnRedirectToIdentityProvider = context =>
		{
			context.ProtocolMessage.SetParameter("acr_values", "mfa");
			return Task.FromResult(0);
		}
	};
});

ASP.NET Core ile OpenID Connect Duende IdentityServer sunucusu örneği Identity

Pages ile Razor ASP.NET Core Identity kullanılarak uygulanan OpenID Connect sunucusunda adlı ErrorEnable2FA.cshtml yeni bir sayfa oluşturulur. Görünüm:

  • , Identity MFA gerektiren ancak kullanıcı tarafından içinde Identityetkinleştirilmemiş bir uygulamadan geliyorsa görüntülenir.
  • Kullanıcıyı bilgilendirip bunu etkinleştirmek için bir bağlantı ekler.
@{
    ViewData["Title"] = "ErrorEnable2FA";
}

<h1>The client application requires you to have MFA enabled. Enable this, try login again.</h1>

<br />

You can enable MFA to login here:

<br />

<a href="~/Identity/Account/Manage/TwoFactorAuthentication">Enable MFA</a>

yönteminde LoginIIdentityServerInteractionService , arabirim uygulaması _interaction OpenID Connect istek parametrelerine erişmek için kullanılır. acr_values parametresine AcrValues özelliği kullanılarak erişilir. İstemci bunu set ile mfa gönderdiğinde, bu daha sonra denetlenebilir.

MFA gerekliyse ve ASP.NET Core'daki Identity kullanıcı MFA'yı etkinleştirdiyse oturum açma işlemi devam eder. Kullanıcının MFA'sı etkin olmadığında, kullanıcı özel görünümüne ErrorEnable2FA.cshtmlyönlendirilir. Ardından ASP.NET Core Identity kullanıcının oturumunu açar.

Fido2Store, kullanıcının özel bir FIDO2 Belirteç Sağlayıcısı kullanarak MFA'yi etkinleştirip etkinleştirmediğini denetlemek için kullanılır.

public async Task<IActionResult> OnPost()
{
	// check if we are in the context of an authorization request
	var context = await _interaction.GetAuthorizationContextAsync(Input.ReturnUrl);

	var requires2Fa = context?.AcrValues.Count(t => t.Contains("mfa")) >= 1;

	var user = await _userManager.FindByNameAsync(Input.Username);
	if (user != null && !user.TwoFactorEnabled && requires2Fa)
	{
		return RedirectToPage("/Home/ErrorEnable2FA/Index");
	}

	// code omitted for brevity

	if (ModelState.IsValid)
	{
		var result = await _signInManager.PasswordSignInAsync(Input.Username, Input.Password, Input.RememberLogin, lockoutOnFailure: true);
		if (result.Succeeded)
		{
			// code omitted for brevity
		}
		if (result.RequiresTwoFactor)
		{
			var fido2ItemExistsForUser = await _fido2Store.GetCredentialsByUserNameAsync(user.UserName);
			if (fido2ItemExistsForUser.Count > 0)
			{
				return RedirectToPage("/Account/LoginFido2Mfa", new { area = "Identity", Input.ReturnUrl, Input.RememberLogin });
			}

			return RedirectToPage("/Account/LoginWith2fa", new { area = "Identity", Input.ReturnUrl, RememberMe = Input.RememberLogin });
		}

		await _events.RaiseAsync(new UserLoginFailureEvent(Input.Username, "invalid credentials", clientId: context?.Client.ClientId));
		ModelState.AddModelError(string.Empty, LoginOptions.InvalidCredentialsErrorMessage);
	}

	// something went wrong, show form with error
	await BuildModelAsync(Input.ReturnUrl);
	return Page();
}

Kullanıcı zaten oturum açmışsa istemci uygulaması:

  • Yine de talebi doğrular amr .
  • MFA'yı ASP.NET Çekirdek Identity görünümüne bir bağlantıyla ayarlayabilir.

acr_values-1 resmi

ASP.NET Core OpenID Connect istemcisini MFA gerektirmeye zorlama

Bu örnekte, oturum açmak için OpenID Connect kullanan bir ASP.NET Temel Razor Sayfa uygulamasının kullanıcıların MFA kullanarak kimlik doğrulaması yapılmasını nasıl gerektirebileceği gösterilmektedir.

MFA gereksinimini doğrulamak için bir IAuthorizationRequirement gereksinim oluşturulur. Bu, MFA gerektiren bir ilke kullanılarak sayfalara eklenir.

using Microsoft.AspNetCore.Authorization;

namespace AspNetCoreRequireMfaOidc;

public class RequireMfa : IAuthorizationRequirement{}

AuthorizationHandler, talebi kullanacak amr ve değerini mfadenetleyecek şekilde uygulanır. amr başarılı bir kimlik doğrulamasında id_token döndürülür ve Kimlik Doğrulama Yöntemi Başvuru Değerleri belirtiminde tanımlanan birçok farklı değere sahip olabilir.

Döndürülen değer, kimliğin kimliğinin nasıl doğrulanmış olduğuna ve OpenID Connect sunucu uygulamasına bağlıdır.

gereksinimini AuthorizationHandlerRequireMfa kullanır ve talebi doğrular amr . OpenID Connect sunucusu, ASP.NET Core Identityile Duende Identity Sunucusu kullanılarak uygulanabilir. Bir kullanıcı TOTP kullanarak oturum açtığında, amr talep bir MFA değeriyle döndürülür. Farklı bir OpenID Connect sunucu uygulaması veya farklı bir MFA türü kullanıyorsanız, amr talep farklı bir değere sahip olabilir veya olabilir. Kodun da bunu kabul etmesi için genişletilmesi gerekir.

public class RequireMfaHandler : AuthorizationHandler<RequireMfa>
{
	protected override Task HandleRequirementAsync(
		AuthorizationHandlerContext context, 
		RequireMfa requirement)
	{
		if (context == null)
			throw new ArgumentNullException(nameof(context));
		if (requirement == null)
			throw new ArgumentNullException(nameof(requirement));

		var amrClaim =
			context.User.Claims.FirstOrDefault(t => t.Type == "amr");

		if (amrClaim != null && amrClaim.Value == Amr.Mfa)
		{
			context.Succeed(requirement);
		}

		return Task.CompletedTask;
	}
}

Program dosyasında, AddOpenIdConnect yöntemi varsayılan sınama şeması olarak kullanılır. Talebi denetlemek amr için kullanılan yetkilendirme işleyicisi, Inversion of Control kapsayıcısına eklenir. Ardından gereksinimi ekleyen RequireMfa bir ilke oluşturulur.

builder.Services.ConfigureApplicationCookie(options =>
        options.Cookie.SecurePolicy =
            CookieSecurePolicy.Always);

builder.Services.AddSingleton<IAuthorizationHandler, RequireMfaHandler>();

builder.Services.AddAuthentication(options =>
{
	options.DefaultScheme =
		CookieAuthenticationDefaults.AuthenticationScheme;
	options.DefaultChallengeScheme =
		OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
	options.SignInScheme =
		CookieAuthenticationDefaults.AuthenticationScheme;
	options.Authority = "https://localhost:44352";
	options.RequireHttpsMetadata = true;
	options.ClientId = "AspNetCoreRequireMfaOidc";
	options.ClientSecret = "AspNetCoreRequireMfaOidcSecret";
	options.ResponseType = "code";
	options.UsePkce = true;	
	options.Scope.Add("profile");
	options.Scope.Add("offline_access");
	options.SaveTokens = true;
});

builder.Services.AddAuthorization(options =>
{
	options.AddPolicy("RequireMfa", policyIsAdminRequirement =>
	{
		policyIsAdminRequirement.Requirements.Add(new RequireMfa());
	});
});

builder.Services.AddRazorPages();

Bu ilke daha sonra sayfada gerektiği gibi kullanılır Razor . İlke, uygulamanın tamamı için de genel olarak eklenebilir.

[Authorize(Policy= "RequireMfa")]
public class IndexModel : PageModel
{
    public void OnGet()
    {
    }
}

Kullanıcı MFA olmadan kimlik doğrulaması yaparsa, amr talep büyük olasılıkla bir pwd değere sahip olur. İstek, sayfaya erişme yetkisine sahip olmayacaktır. Kullanıcı varsayılan değerleri kullanarak Account/AccessDenied sayfasına yönlendirilir. Bu davranış değiştirilebilir veya burada kendi özel mantığınızı uygulayabilirsiniz. Bu örnekte, geçerli kullanıcının hesabı için MFA ayarlayabilmesi için bir bağlantı eklenir.

@page
@model AspNetCoreRequireMfaOidc.AccessDeniedModel
@{
    ViewData["Title"] = "AccessDenied";
    Layout = "~/Pages/Shared/_Layout.cshtml";
}

<h1>AccessDenied</h1>

You require MFA to login here

<a href="https://localhost:44352/Manage/TwoFactorAuthentication">Enable MFA</a>

Artık sayfaya veya web sitesine yalnızca MFA ile kimlik doğrulayan kullanıcılar erişebilir. Farklı MFA türleri kullanılıyorsa veya 2FA uygunsa, amr talep farklı değerlere sahip olur ve doğru işlenmesi gerekir. Farklı OpenID Connect sunucuları da bu talep için farklı değerler döndürür ve Kimlik Doğrulama Yöntemi Başvuru Değerleri belirtimini izlemeyebilir.

MFA olmadan oturum açarken (örneğin, yalnızca bir parola kullanarak):

  • amr şu değere pwd sahiptir:

    amr pwd değerine sahiptir

  • Erişim reddedildi:

    Erişim reddedildi

Alternatif olarak, ile IdentityOTP kullanarak oturum açma:

ile OTP kullanarak oturum açma Identity

Ek kaynaklar

Tarafından Damien Bowden

Örnek kodu görüntüleme veya indirme (damienbod/AspNetCoreHybridFlowWithApi GitHub deposu)

Çok faktörlü kimlik doğrulaması (MFA), bir kullanıcının ek tanımlama biçimleri için oturum açma olayı sırasında istendiği bir işlemdir. Bu istem, bir cep telefonundan kod girmek, FIDO2 anahtarı kullanmak veya parmak izi taraması sağlamak olabilir. İkinci bir kimlik doğrulama biçimine ihtiyacınız olduğunda güvenlik iyileştirilmiştir. Ek faktör bir saldırgan tarafından kolayca elde edilemez veya çoğaltılamaz.

Bu makale aşağıdaki alanları kapsar:

  • MFA nedir ve hangi MFA akışları önerilir?
  • ASP.NET Core kullanarak yönetim sayfaları için MFA'yi yapılandırma Identity
  • OpenID Connect sunucusuna MFA oturum açma gereksinimi gönderme
  • ASP.NET Core OpenID Connect istemcisini MFA gerektirmeye zorlama

MFA, 2FA

MFA, bildiğiniz, sahip olduğunuz bir şey veya kullanıcının kimlik doğrulaması için biyometrik doğrulama gibi bir kimlik için en az iki veya daha fazla türde kanıt gerektirir.

İki öğeli kimlik doğrulaması (2FA), MFA'nın bir alt kümesi gibidir, ancak MFA'nın kimliği kanıtlamak için iki veya daha fazla faktör gerektirmesi farktır.

MFA TOTP (Zamana Dayalı Tek Seferlik Parola Algoritması)

TOTP kullanan MFA, ASP.NET Core Identitykullanan desteklenen bir uygulamadır. Bu, aşağıdakiler dahil olmak üzere tüm uyumlu kimlik doğrulayıcı uygulamalarıyla birlikte kullanılabilir:

  • Microsoft Authenticator Uygulaması
  • Google Authenticator Uygulaması

Uygulama ayrıntıları için aşağıdaki bağlantıya bakın:

ASP.NET Core'da TOTP kimlik doğrulayıcı uygulamaları için QR Kodu oluşturmayı etkinleştirme

MFA geçiş anahtarları/FIDO2 veya parolasız

passkeys/FIDO2 şu anda:

  • MFA'ya ulaşmanın en güvenli yolu.
  • Kimlik avı saldırılarına karşı koruma sağlayan MFA. (Sertifika kimlik doğrulaması ve İş için Windows'un yanı sıra)

Şu anda ASP.NET Core doğrudan geçiş anahtarlarını/FIDO2'yi desteklememektedir. Geçiş anahtarları/FIDO2, MFA veya parolasız akışlar için kullanılabilir.

Microsoft Entra ID, geçiş anahtarları/FIDO2 ve parolasız akışlar için destek sağlar. Daha fazla bilgi için bkz . Parolasız kimlik doğrulama seçenekleri.

Parolasız MFA'nın diğer biçimleri kimlik avına karşı koruma sağlamaz veya korumayabilir.

MFA SMS

SMS ile MFA, parola kimlik doğrulaması (tek faktör) ile karşılaştırıldığında güvenliği büyük ölçüde artırır. Ancak SMS'in ikinci bir faktör olarak kullanılması artık önerilmez. Bu tür bir uygulama için çok fazla bilinen saldırı vektörleri var.

NIST yönergeleri

ASP.NET Core kullanarak yönetim sayfaları için MFA'yi yapılandırma Identity

MFA, kullanıcılara ASP.NET Core Identity uygulamasındaki hassas sayfalara erişmeye zorlanabilir. Bu, farklı kimlikler için farklı erişim düzeylerinin bulunduğu uygulamalar için yararlı olabilir. Örneğin, kullanıcılar profil verilerini parolayla oturum açma bilgilerini kullanarak görüntüleyebilir, ancak yöneticinin yönetim sayfalarına erişmek için MFA kullanması gerekebilir.

MFA talebiyle oturum açmayı genişletme

Tanıtım kodu ve Razor Sayfaları ile Identity ASP.NET Core kullanılarak ayarlanır. AddIdentity yöntemi yerine kullanılırAddDefaultIdentity, bu nedenle başarılı bir oturum açma sonrasında kimliğe talep eklemek için bir IUserClaimsPrincipalFactory uygulama kullanılabilir.

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

    services.AddIdentity<IdentityUser, IdentityRole>(
            options => options.SignIn.RequireConfirmedAccount = false)
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    services.AddSingleton<IEmailSender, EmailSender>();
    services.AddScoped<IUserClaimsPrincipalFactory<IdentityUser>, 
        AdditionalUserClaimsPrincipalFactory>();

    services.AddAuthorization(options =>
        options.AddPolicy("TwoFactorEnabled",
            x => x.RequireClaim("amr", "mfa")));

    services.AddRazorPages();
}

sınıfı, AdditionalUserClaimsPrincipalFactory talebi yalnızca başarılı bir oturum açma sonrasında kullanıcı taleplerine ekler amr . Talebin değeri veritabanından okunur. Talep buraya eklenir çünkü kullanıcının yalnızca kimlik MFA ile oturum açmışsa daha yüksek korumalı görünüme erişmesi gerekir. Veritabanı görünümü talebi kullanmak yerine doğrudan veritabanından okunursa, MFA etkinleştirildikten sonra doğrudan MFA olmadan görünüme erişmek mümkündür.

using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;

namespace IdentityStandaloneMfa
{
    public class AdditionalUserClaimsPrincipalFactory : 
        UserClaimsPrincipalFactory<IdentityUser, IdentityRole>
    {
        public AdditionalUserClaimsPrincipalFactory( 
            UserManager<IdentityUser> userManager,
            RoleManager<IdentityRole> roleManager, 
            IOptions<IdentityOptions> optionsAccessor) 
            : base(userManager, roleManager, optionsAccessor)
        {
        }

        public async override Task<ClaimsPrincipal> CreateAsync(IdentityUser user)
        {
            var principal = await base.CreateAsync(user);
            var identity = (ClaimsIdentity)principal.Identity;

            var claims = new List<Claim>();

            if (user.TwoFactorEnabled)
            {
                claims.Add(new Claim("amr", "mfa"));
            }
            else
            {
                claims.Add(new Claim("amr", "pwd"));
            }

            identity.AddClaims(claims);
            return principal;
        }
    }
}

Identity Hizmet kurulumu sınıfında değiştiğindenStartup, düzenlerinin Identity güncelleştirilmiş olması gerekir. Identity Sayfaları uygulamaya iskelesi oluşturun. Dosyadaki Identity/Account/Manage/_Layout.cshtml düzeni tanımlayın.

@{
    Layout = "/Pages/Shared/_Layout.cshtml";
}

Ayrıca, sayfalardan tüm yönetme sayfaları için düzeni atayın Identity :

@{
    Layout = "_Layout.cshtml";
}

Yönetim sayfasında MFA gereksinimini doğrulama

Yönetim Razor Sayfası, kullanıcının MFA kullanarak oturum açtığını doğrular. yönteminde OnGet kimlik, kullanıcı taleplerine erişmek için kullanılır. Talep amr değeri mfaiçin denetlendi. Kimlikte bu talep yoksa veya ise false, sayfa MFA'yı Etkinleştir sayfasına yönlendirilir. Kullanıcı MFA olmadan zaten oturum açtığından bu mümkündür.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace IdentityStandaloneMfa
{
    public class AdminModel : PageModel
    {
        public IActionResult OnGet()
        {
            var claimTwoFactorEnabled = 
                User.Claims.FirstOrDefault(t => t.Type == "amr");

            if (claimTwoFactorEnabled != null && 
                "mfa".Equals(claimTwoFactorEnabled.Value))
            {
                // You logged in with MFA, do the administrative stuff
            }
            else
            {
                return Redirect(
                    "/Identity/Account/Manage/TwoFactorAuthentication");
            }

            return Page();
        }
    }
}

Kullanıcı oturum açma bilgilerini değiştirmek için kullanıcı arabirimi mantığı

Program dosyasına bir yetkilendirme ilkesi eklendi. İlke, değerine mfasahip talebi gerektiriramr.

builder.Services.AddAuthorization(options =>
    options.AddPolicy("TwoFactorEnabled",
        x => x.RequireClaim("amr", "mfa")));

Bu ilke daha sonra görünümde _Layout yönetici menüsünü şu uyarıyla göstermek veya gizlemek için kullanılabilir:

@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@inject IAuthorizationService AuthorizationService

Kimlik MFA kullanarak oturum açtıysa, Yönetici menüsü araç ipucu uyarısı olmadan görüntülenir. Kullanıcı MFA olmadan oturum açtığında, kullanıcıyı bilgilendiren araç ipucuyla birlikte Yönetici (Etkin Değil) menüsü görüntülenir (uyarı açıklanmaktadır).

@if (SignInManager.IsSignedIn(User))
{
    @if ((AuthorizationService.AuthorizeAsync(User, "TwoFactorEnabled")).Result.Succeeded)
    {
        <li class="nav-item">
            <a class="nav-link text-dark" asp-area="" asp-page="/Admin">Admin</a>
        </li>
    }
    else
    {
        <li class="nav-item">
            <a class="nav-link text-dark" asp-area="" asp-page="/Admin" 
               id="tooltip-demo"  
               data-toggle="tooltip" 
               data-placement="bottom" 
               title="MFA is NOT enabled. This is required for the Admin Page. If you have activated MFA, then logout, login again.">
                Admin (Not Enabled)
            </a>
        </li>
    }
}

Kullanıcı MFA olmadan oturum açarsa uyarı görüntülenir:

Yönetici MFA kimlik doğrulaması

Kullanıcı, Yönetici bağlantısına tıklandığında MFA etkinleştirme görünümüne yönlendirilir:

Yönetici MFA kimlik doğrulamayı etkinleştirir

OpenID Connect sunucusuna MFA oturum açma gereksinimi gönderme

parametresi, acr_values bir kimlik doğrulama isteğinde mfa istemciden sunucuya gerekli değeri geçirmek için kullanılabilir.

Not

Bunun acr_values çalışması için parametresinin OpenID Connect sunucusunda işlenmesi gerekir.

OpenID Connect ASP.NET Core istemcisi

ASP.NET Core Razor Pages OpenID Connect istemci uygulaması, OpenID Connect sunucusunda oturum açmak için yöntemini kullanır AddOpenIdConnect . acr_values parametresi değeriyle mfa ayarlanır ve kimlik doğrulama isteğiyle gönderilir. OpenIdConnectEvents bunu eklemek için kullanılır.

Önerilen acr_values parametre değerleri için bkz . Kimlik Doğrulama Yöntemi Başvuru Değerleri.

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(options =>
    {
        options.DefaultScheme =
            CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme =
            OpenIdConnectDefaults.AuthenticationScheme;
    })
    .AddCookie()
    .AddOpenIdConnect(options =>
    {
        options.SignInScheme =
            CookieAuthenticationDefaults.AuthenticationScheme;
        options.Authority = "<OpenID Connect server URL>";
        options.RequireHttpsMetadata = true;
        options.ClientId = "<OpenID Connect client ID>";
        options.ClientSecret = "<>";
        options.ResponseType = "code";
        options.UsePkce = true;	
        options.Scope.Add("profile");
        options.Scope.Add("offline_access");
        options.SaveTokens = true;
        options.Events = new OpenIdConnectEvents
        {
            OnRedirectToIdentityProvider = context =>
            {
                context.ProtocolMessage.SetParameter("acr_values", "mfa");
                return Task.FromResult(0);
            }
        };
    });

ASP.NET Core ile örnek OpenID Connect IdentityServer 4 sunucusu Identity

MVC görünümleriyle ASP.NET Core Identity kullanılarak uygulanan OpenID Connect sunucusunda adlı ErrorEnable2FA.cshtml yeni bir görünüm oluşturulur. Görünüm:

  • , Identity MFA gerektiren ancak kullanıcı tarafından içinde Identityetkinleştirilmemiş bir uygulamadan geliyorsa görüntülenir.
  • Kullanıcıyı bilgilendirip bunu etkinleştirmek için bir bağlantı ekler.
@{
    ViewData["Title"] = "ErrorEnable2FA";
}

<h1>The client application requires you to have MFA enabled. Enable this, try login again.</h1>

<br />

You can enable MFA to login here:

<br />

<a asp-controller="Manage" asp-action="TwoFactorAuthentication">Enable MFA</a>

yönteminde LoginIIdentityServerInteractionService , arabirim uygulaması _interaction OpenID Connect istek parametrelerine erişmek için kullanılır. acr_values parametresine AcrValues özelliği kullanılarak erişilir. İstemci bunu set ile mfa gönderdiğinde, bu daha sonra denetlenebilir.

MFA gerekliyse ve ASP.NET Core'daki Identity kullanıcı MFA'yı etkinleştirdiyse oturum açma işlemi devam eder. Kullanıcının MFA'sı etkin olmadığında, kullanıcı özel görünümüne ErrorEnable2FA.cshtmlyönlendirilir. Ardından ASP.NET Core Identity kullanıcının oturumunu açar.

//
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginInputModel model)
{
    var returnUrl = model.ReturnUrl;
    var context = 
        await _interaction.GetAuthorizationContextAsync(returnUrl);
    var requires2Fa = 
        context?.AcrValues.Count(t => t.Contains("mfa")) >= 1;

    var user = await _userManager.FindByNameAsync(model.Email);
    if (user != null && !user.TwoFactorEnabled && requires2Fa)
    {
        return RedirectToAction(nameof(ErrorEnable2FA));
    }

    // code omitted for brevity

ExternalLoginCallback yöntemi yerel Identity oturum açma gibi çalışır. AcrValues özelliği değer için denetlendimfa. mfa Değer varsa, oturum açma tamamlanmadan önce MFA zorlanır (örneğin, görünüme ErrorEnable2FA yönlendirilir).

//
// GET: /Account/ExternalLoginCallback
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> ExternalLoginCallback(
    string returnUrl = null,
    string remoteError = null)
{
    var context =
        await _interaction.GetAuthorizationContextAsync(returnUrl);
    var requires2Fa =
        context?.AcrValues.Count(t => t.Contains("mfa")) >= 1;

    if (remoteError != null)
    {
        ModelState.AddModelError(
            string.Empty,
            _sharedLocalizer["EXTERNAL_PROVIDER_ERROR", 
            remoteError]);
        return View(nameof(Login));
    }
    var info = await _signInManager.GetExternalLoginInfoAsync();

    if (info == null)
    {
        return RedirectToAction(nameof(Login));
    }

    var email = info.Principal.FindFirstValue(ClaimTypes.Email);

    if (!string.IsNullOrEmpty(email))
    {
        var user = await _userManager.FindByNameAsync(email);
        if (user != null && !user.TwoFactorEnabled && requires2Fa)
        {
            return RedirectToAction(nameof(ErrorEnable2FA));
        }
    }

    // Sign in the user with this external login provider if the user already has a login.
    var result = await _signInManager
        .ExternalLoginSignInAsync(
            info.LoginProvider, 
            info.ProviderKey, 
            isPersistent: 
            false);

    // code omitted for brevity

Kullanıcı zaten oturum açmışsa istemci uygulaması:

  • Yine de talebi doğrular amr .
  • MFA'yı ASP.NET Çekirdek Identity görünümüne bir bağlantıyla ayarlayabilir.

acr_values-1 resmi

ASP.NET Core OpenID Connect istemcisini MFA gerektirmeye zorlama

Bu örnekte, oturum açmak için OpenID Connect kullanan bir ASP.NET Temel Razor Sayfa uygulamasının kullanıcıların MFA kullanarak kimlik doğrulaması yapılmasını nasıl gerektirebileceği gösterilmektedir.

MFA gereksinimini doğrulamak için bir IAuthorizationRequirement gereksinim oluşturulur. Bu, MFA gerektiren bir ilke kullanılarak sayfalara eklenir.

using Microsoft.AspNetCore.Authorization;

namespace AspNetCoreRequireMfaOidc
{
    public class RequireMfa : IAuthorizationRequirement{}
}

AuthorizationHandler, talebi kullanacak amr ve değerini mfadenetleyecek şekilde uygulanır. amr başarılı bir kimlik doğrulamasında id_token döndürülür ve Kimlik Doğrulama Yöntemi Başvuru Değerleri belirtiminde tanımlanan birçok farklı değere sahip olabilir.

Döndürülen değer, kimliğin kimliğinin nasıl doğrulanmış olduğuna ve OpenID Connect sunucu uygulamasına bağlıdır.

gereksinimini AuthorizationHandlerRequireMfa kullanır ve talebi doğrular amr . OpenID Connect sunucusu, ASP.NET Core Identityile Server4 kullanılarak Identityuygulanabilir. Bir kullanıcı TOTP kullanarak oturum açtığında, amr talep bir MFA değeriyle döndürülür. Farklı bir OpenID Connect sunucu uygulaması veya farklı bir MFA türü kullanıyorsanız, amr talep farklı bir değere sahip olabilir veya olabilir. Kodun da bunu kabul etmesi için genişletilmesi gerekir.

public class RequireMfaHandler : AuthorizationHandler<RequireMfa>
{
	protected override Task HandleRequirementAsync(
		AuthorizationHandlerContext context, 
		RequireMfa requirement)
	{
		if (context == null)
			throw new ArgumentNullException(nameof(context));
		if (requirement == null)
			throw new ArgumentNullException(nameof(requirement));

		var amrClaim =
			context.User.Claims.FirstOrDefault(t => t.Type == "amr");

		if (amrClaim != null && amrClaim.Value == Amr.Mfa)
		{
			context.Succeed(requirement);
		}

		return Task.CompletedTask;
	}
}

yönteminde Startup.ConfigureServicesAddOpenIdConnect , yöntemi varsayılan sınama şeması olarak kullanılır. Talebi denetlemek amr için kullanılan yetkilendirme işleyicisi, Inversion of Control kapsayıcısına eklenir. Ardından gereksinimi ekleyen RequireMfa bir ilke oluşturulur.

public void ConfigureServices(IServiceCollection services)
{
    services.ConfigureApplicationCookie(options =>
        options.Cookie.SecurePolicy =
            CookieSecurePolicy.Always);

    services.AddSingleton<IAuthorizationHandler, RequireMfaHandler>();

    services.AddAuthentication(options =>
    {
        options.DefaultScheme =
            CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme =
            OpenIdConnectDefaults.AuthenticationScheme;
    })
    .AddCookie()
    .AddOpenIdConnect(options =>
    {
        options.SignInScheme =
            CookieAuthenticationDefaults.AuthenticationScheme;
        options.Authority = "https://localhost:44352";
        options.RequireHttpsMetadata = true;
        options.ClientId = "AspNetCoreRequireMfaOidc";
        options.ClientSecret = "AspNetCoreRequireMfaOidcSecret";
        options.ResponseType = "code";
        options.UsePkce = true;	
        options.Scope.Add("profile");
        options.Scope.Add("offline_access");
        options.SaveTokens = true;
    });

    services.AddAuthorization(options =>
    {
        options.AddPolicy("RequireMfa", policyIsAdminRequirement =>
        {
            policyIsAdminRequirement.Requirements.Add(new RequireMfa());
        });
    });

    services.AddRazorPages();
}

Bu ilke daha sonra sayfada gerektiği gibi kullanılır Razor . İlke, uygulamanın tamamı için de genel olarak eklenebilir.

[Authorize(Policy= "RequireMfa")]
public class IndexModel : PageModel
{
    public void OnGet()
    {
    }
}

Kullanıcı MFA olmadan kimlik doğrulaması yaparsa, amr talep büyük olasılıkla bir pwd değere sahip olur. İstek, sayfaya erişme yetkisine sahip olmayacaktır. Kullanıcı varsayılan değerleri kullanarak Account/AccessDenied sayfasına yönlendirilir. Bu davranış değiştirilebilir veya burada kendi özel mantığınızı uygulayabilirsiniz. Bu örnekte, geçerli kullanıcının hesabı için MFA ayarlayabilmesi için bir bağlantı eklenir.

@page
@model AspNetCoreRequireMfaOidc.AccessDeniedModel
@{
    ViewData["Title"] = "AccessDenied";
    Layout = "~/Pages/Shared/_Layout.cshtml";
}

<h1>AccessDenied</h1>

You require MFA to login here

<a href="https://localhost:44352/Manage/TwoFactorAuthentication">Enable MFA</a>

Artık sayfaya veya web sitesine yalnızca MFA ile kimlik doğrulayan kullanıcılar erişebilir. Farklı MFA türleri kullanılıyorsa veya 2FA uygunsa, amr talep farklı değerlere sahip olur ve doğru işlenmesi gerekir. Farklı OpenID Connect sunucuları da bu talep için farklı değerler döndürür ve Kimlik Doğrulama Yöntemi Başvuru Değerleri belirtimini izlemeyebilir.

MFA olmadan oturum açarken (örneğin, yalnızca bir parola kullanarak):

  • amr şu değere pwd sahiptir:

    amr pwd değerine sahiptir

  • Erişim reddedildi:

    Erişim reddedildi

Alternatif olarak, ile IdentityOTP kullanarak oturum açma:

ile OTP kullanarak oturum açma Identity

Ek kaynaklar