Uwierzytelnianie wieloskładnikowe w usłudze ASP.NET Core
Uwaga
Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
Ważne
Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.
Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
Autor: Damien Bowden
Uwierzytelnianie wieloskładnikowe (MFA) to proces, w którym użytkownik jest proszony podczas logowania w celu uzyskania dodatkowych form identyfikacji. Ten monit może być wprowadzenie kodu z telefonu komórkowego, użycie klucza FIDO2 lub dostarczenie skanowania odciskiem palca. Jeśli potrzebujesz drugiej formy uwierzytelniania, zabezpieczenia są ulepszone. Dodatkowy czynnik nie jest łatwo uzyskiwany ani duplikowany przez cyberatakę.
W tym artykule opisano następujące obszary:
- Co to jest uwierzytelnianie wieloskładnikowe i jakie przepływy uwierzytelniania wieloskładnikowego są zalecane
- Konfigurowanie uwierzytelniania wieloskładnikowego dla stron administracyjnych przy użyciu platformy ASP.NET Core Identity
- Wysyłanie wymagania logowania wieloskładnikowego do serwera OpenID Connect
- Wymuszanie ASP.NET klienta OpenID Connect w celu wymagania uwierzytelniania wieloskładnikowego
Uwierzytelnianie wieloskładnikowe, 2FA
Uwierzytelnianie wieloskładnikowe wymaga co najmniej dwóch typów dowodu dla identity czegoś podobnego do posiadanego, posiadanego lub biometrycznego sprawdzania poprawności w celu uwierzytelnienia użytkownika.
Uwierzytelnianie dwuskładnikowe (2FA) jest jak podzbiór uwierzytelniania wieloskładnikowego, ale różnica polega na tym, że uwierzytelnianie wieloskładnikowe może wymagać co najmniej dwóch czynników, aby udowodnić wartość identity.
2FA jest domyślnie obsługiwane w przypadku korzystania z ASP.NET Core Identity. Aby włączyć lub wyłączyć uwierzytelnianie 2FA dla określonego użytkownika, ustaw IdentityUser<TKey>.TwoFactorEnabled właściwość . Domyślny interfejs użytkownika platformy ASP.NET Core Identity zawiera strony służące do konfigurowania uwierzytelniania 2FA.
MFA TOTP (algorytm haseł jednorazowych oparty na czasie)
Uwierzytelnianie wieloskładnikowe przy użyciu protokołu TOTP jest domyślnie obsługiwane w przypadku korzystania z usługi ASP.NET Core Identity. Takie podejście może być używane razem z dowolną zgodną aplikacją wystawcy uwierzytelniania, w tym:
- Microsoft Authenticator
- Google Authenticator
Aby uzyskać szczegółowe informacje o implementacji, zobacz Włączanie generowania kodu QR dla aplikacji wystawcy uwierzytelniania TOTP w programie ASP.NET Core.
Aby wyłączyć obsługę protokołu MFA TOTP, skonfiguruj uwierzytelnianie przy użyciu AddIdentity zamiast AddDefaultIdentity. AddDefaultIdentity
wywołuje AddDefaultTokenProviders wewnętrznie, co rejestruje wielu dostawców tokenów, w tym jednego dla uwierzytelniania wieloskładnikowego TOTP. Aby zarejestrować tylko określonych dostawców tokenów, wywołaj AddTokenProvider dla każdego wymaganego dostawcy. Aby uzyskać więcej informacji na temat dostępnych dostawców tokenów, zobacz źródło AddDefaultTokenProviders w witrynie GitHub.
Hasła uwierzytelniania wieloskładnikowego/FIDO2 lub bez hasła
Klucz dostępu/FIDO2 jest obecnie:
- Najbezpieczniejszy sposób osiągnięcia uwierzytelniania wieloskładnikowego.
- Uwierzytelnianie wieloskładnikowe chroniące przed atakami wyłudzającymi informacje. (Oprócz uwierzytelniania certyfikatów i systemu Windows dla firm)
Obecnie ASP.NET Core nie obsługuje bezpośrednio kluczy dostępu/FIDO2. W przypadku przepływów MFA lub bez hasła można używać kluczy dostępu/FIDO2.
Identyfikator Entra firmy Microsoft zapewnia obsługę przepływów passkeys/FIDO2 i bez hasła. Aby uzyskać więcej informacji, zobacz Opcje uwierzytelniania bez hasła.
Inne formy uwierzytelniania wieloskładnikowego bez hasła nie są chronione przed wyłudzaniem informacji.
Wiadomość SMS dotycząca uwierzytelniania wieloskładnikowego
Uwierzytelnianie wieloskładnikowe z programem SMS zwiększa bezpieczeństwo w porównaniu z uwierzytelnianiem przy użyciu hasła (pojedynczy czynnik). Jednak używanie wiadomości SMS jako drugiego czynnika nie jest już zalecane. Dla tego typu implementacji istnieje zbyt wiele znanych wektorów ataków.
Konfigurowanie uwierzytelniania wieloskładnikowego dla stron administracyjnych przy użyciu platformy ASP.NET Core Identity
Uwierzytelnianie wieloskładnikowe można wymusić na użytkownikach dostęp do poufnych stron w aplikacji ASP.NET Core Identity . Może to być przydatne w przypadku aplikacji, w których istnieją różne poziomy dostępu dla różnych tożsamości. Na przykład użytkownicy mogą wyświetlać dane profilu przy użyciu logowania przy użyciu hasła, ale administrator musi użyć uwierzytelniania wieloskładnikowego w celu uzyskania dostępu do stron administracyjnych.
Rozszerzanie nazwy logowania przy użyciu oświadczenia uwierzytelniania wieloskładnikowego
Kod demonstracyjny jest konfigurowany przy użyciu platformy ASP.NET Core z usługami Identity i Razor Pages. Metoda AddIdentity
jest używana zamiast AddDefaultIdentity
jednej, więc implementacja IUserClaimsPrincipalFactory
może służyć do dodawania oświadczeń do identity po pomyślnym zalogowaniu.
Ostrzeżenie
W tym artykule przedstawiono użycie parametry połączenia. W przypadku lokalnej bazy danych użytkownik nie musi być uwierzytelniany, ale w środowisku produkcyjnym parametry połączenia czasami zawiera hasło do uwierzytelniania. Poświadczenie hasła właściciela zasobu (ROPC) jest zagrożeniem bezpieczeństwa, którego należy unikać w produkcyjnych bazach danych. Aplikacje produkcyjne powinny korzystać z najbezpieczniejszego dostępnego przepływu uwierzytelniania. Aby uzyskać więcej informacji na temat uwierzytelniania aplikacji wdrożonych w środowiskach testowych lub produkcyjnych, zobacz Bezpieczne przepływy uwierzytelniania.
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();
Klasa AdditionalUserClaimsPrincipalFactory
dodaje amr
oświadczenie do oświadczenia użytkownika tylko po pomyślnym zalogowaniu. Wartość oświadczenia jest odczytywana z bazy danych. Oświadczenie jest dodawane tutaj, ponieważ użytkownik powinien uzyskać dostęp tylko do wyższego widoku chronionego, jeśli identity użytkownik zalogował się przy użyciu uwierzytelniania wieloskładnikowego. Jeśli widok bazy danych jest odczytywany bezpośrednio z bazy danych zamiast korzystać z oświadczenia, można uzyskać dostęp do widoku bez uwierzytelniania wieloskładnikowego bezpośrednio po aktywowaniu uwierzytelniania wieloskładnikowego.
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 Ponieważ konfiguracja usługi zmieniła się w Startup
klasie, układy Identity muszą zostać zaktualizowane. Tworzenie szkieletu Identity stron w aplikacji. Zdefiniuj Identity/Account/Manage/_Layout.cshtml
układ w pliku.
@{
Layout = "/Pages/Shared/_Layout.cshtml";
}
Przypisz również układ dla wszystkich stron zarządzania na Identity stronach:
@{
Layout = "_Layout.cshtml";
}
Weryfikowanie wymagania uwierzytelniania wieloskładnikowego na stronie administracyjnej
Strona administracyjna Razor sprawdza, czy użytkownik zalogował się przy użyciu uwierzytelniania wieloskładnikowego. W metodzie OnGet
identity parametr jest używany do uzyskiwania dostępu do oświadczeń użytkownika. Oświadczenie amr
jest sprawdzane pod kątem wartości mfa
. identity Jeśli brakuje tego oświadczenia lub jest false
, strona przekierowuje do strony Włączanie uwierzytelniania wieloskładnikowego. Jest to możliwe, ponieważ użytkownik zalogował się już, ale bez uwierzytelniania wieloskładnikowego.
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();
}
}
}
Logika interfejsu użytkownika w celu przełączania informacji logowania użytkownika
Zasady autoryzacji zostały dodane podczas uruchamiania. Zasady wymagają amr
oświadczenia o wartości mfa
.
services.AddAuthorization(options =>
options.AddPolicy("TwoFactorEnabled",
x => x.RequireClaim("amr", "mfa")));
Te zasady można następnie użyć w _Layout
widoku, aby wyświetlić lub ukryć menu Administratora z ostrzeżeniem:
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@inject IAuthorizationService AuthorizationService
Jeśli użytkownik identity zalogował się przy użyciu uwierzytelniania wieloskładnikowego, menu Administratora jest wyświetlane bez ostrzeżenia etykietki narzędzia. Gdy użytkownik zalogował się bez uwierzytelniania wieloskładnikowego, zostanie wyświetlone menu Administrator (nie włączono) wraz z etykietkę narzędzia informującą użytkownika (wyjaśnienie ostrzeżenia).
@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>
}
}
Jeśli użytkownik zaloguje się bez uwierzytelniania wieloskładnikowego, zostanie wyświetlone ostrzeżenie:
Użytkownik jest przekierowywany do widoku włączania uwierzytelniania wieloskładnikowego po kliknięciu linku Administratora :
Wysyłanie wymagania logowania wieloskładnikowego do serwera OpenID Connect
Parametr acr_values
może służyć do przekazywania wymaganej mfa
wartości z klienta do serwera w żądaniu uwierzytelniania.
Uwaga
Aby acr_values
ten parametr działał, należy obsłużyć na serwerze OpenID Connect.
Klient OpenID Connect ASP.NET Core
Aplikacja kliencka OpenID Connect ASP.NET Core Razor Pages używa AddOpenIdConnect
metody logowania do serwera OpenID Connect. Parametr acr_values
jest ustawiany z wartością mfa
i wysyłany z żądaniem uwierzytelniania. Element służy do dodawania OpenIdConnectEvents
tego elementu.
Aby uzyskać zalecane acr_values
wartości parametrów, zobacz Wartości referencyjne metody uwierzytelniania.
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");
});
Przykładowy serwer OpenID Connect Duende IdentityServer z ASP.NET Core Identity
Na serwerze OpenID Connect, który jest implementowany przy użyciu ASP.NET Core Identity ze stronami Razor , zostanie utworzona nowa strona o nazwie ErrorEnable2FA.cshtml
. Widok:
- Wyświetla, czy Identity element pochodzi z aplikacji wymagającej uwierzytelniania wieloskładnikowego, ale użytkownik nie aktywował go w programie Identity.
- Informuje użytkownika i dodaje link, aby to aktywować.
@{
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>
W metodzie implementacja _interaction
interfejsu Login
IIdentityServerInteractionService
jest używana do uzyskiwania dostępu do parametrów żądania OpenID Connect. Dostęp acr_values
do parametru AcrValues
jest uzyskiwany przy użyciu właściwości . Po wysłaniu tego polecenia przez klienta z mfa
zestawem można to sprawdzić.
Jeśli uwierzytelnianie wieloskładnikowe jest wymagane, a użytkownik w aplikacji ASP.NET Core Identity ma włączoną uwierzytelnianie wieloskładnikowe, logowanie będzie kontynuowane. Gdy użytkownik nie ma włączonej uwierzytelniania wieloskładnikowego, użytkownik jest przekierowywany do widoku ErrorEnable2FA.cshtml
niestandardowego . Następnie ASP.NET Core Identity loguje użytkownika.
Magazyn Fido2Store służy do sprawdzania, czy użytkownik aktywował uwierzytelnianie wieloskładnikowe przy użyciu niestandardowego dostawcy tokenów FIDO2.
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();
}
Jeśli użytkownik jest już zalogowany, aplikacja kliencka:
- Nadal sprawdza poprawność
amr
oświadczenia. - Można skonfigurować uwierzytelnianie wieloskładnikowe za pomocą linku do widoku ASP.NET Core Identity .
Wymuszanie ASP.NET klienta OpenID Connect w celu wymagania uwierzytelniania wieloskładnikowego
W tym przykładzie pokazano, jak aplikacja ASP.NET Core Razor Page, która używa interfejsu OpenID Connect do logowania, może wymagać uwierzytelnienia użytkowników przy użyciu uwierzytelniania wieloskładnikowego.
Aby zweryfikować wymaganie uwierzytelniania wieloskładnikowego, IAuthorizationRequirement
zostanie utworzone wymaganie. Zostanie to dodane do stron przy użyciu zasad wymagających uwierzytelniania wieloskładnikowego.
using Microsoft.AspNetCore.Authorization;
namespace AspNetCoreRequireMfaOidc;
public class RequireMfa : IAuthorizationRequirement{}
Zaimplementowano AuthorizationHandler
element , który będzie używał amr
oświadczenia i sprawdzał wartość mfa
. Element amr
jest zwracany w elemencie id_token
pomyślnego uwierzytelniania i może mieć wiele różnych wartości zdefiniowanych w specyfikacji Wartości referencyjne metody uwierzytelniania.
Zwrócona wartość zależy od sposobu identity uwierzytelnienia i implementacji serwera OpenID Connect.
RequireMfa
Używa AuthorizationHandler
wymagania i weryfikuje amr
oświadczenie. Serwer OpenID Connect można zaimplementować przy użyciu serwera Duende Identity z programem ASP.NET Core Identity. Gdy użytkownik loguje się przy użyciu protokołu TOTP, amr
oświadczenie jest zwracane z wartością uwierzytelniania wieloskładnikowego. Jeśli używasz innej implementacji serwera OpenID Connect lub innego typu uwierzytelniania wieloskładnikowego, amr
oświadczenie będzie lub może mieć inną wartość. Aby można było również zaakceptować ten kod, należy go rozszerzyć.
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;
}
}
W pliku AddOpenIdConnect
programu metoda jest używana jako domyślny schemat wyzwania. Procedura obsługi autoryzacji używana do sprawdzania amr
oświadczenia jest dodawana do kontenera Inversion of Control. Następnie zostanie utworzona zasada, która dodaje RequireMfa
wymaganie.
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();
Te zasady są następnie używane na stronie zgodnie z Razor wymaganiami. Zasady można również dodać globalnie dla całej aplikacji.
[Authorize(Policy= "RequireMfa")]
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
Jeśli użytkownik uwierzytelnia się bez uwierzytelniania wieloskładnikowego, amr
oświadczenie prawdopodobnie będzie miało pwd
wartość. Żądanie nie będzie autoryzowane w celu uzyskania dostępu do strony. Przy użyciu wartości domyślnych użytkownik zostanie przekierowany do strony Account/AccessDenied . To zachowanie można zmienić lub zaimplementować własną logikę niestandardową tutaj. W tym przykładzie zostanie dodany link, aby prawidłowy użytkownik mógł skonfigurować uwierzytelnianie wieloskładnikowe dla swojego konta.
@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>
Teraz tylko użytkownicy uwierzytelnieni za pomocą uwierzytelniania wieloskładnikowego mogą uzyskiwać dostęp do strony lub witryny internetowej. Jeśli są używane różne typy uwierzytelniania wieloskładnikowego lub jeśli uwierzytelnianie 2FA jest w porządku, amr
oświadczenie będzie miało różne wartości i musi zostać prawidłowo przetworzone. Różne serwery OpenID Connect zwracają również różne wartości dla tego oświadczenia i mogą nie być zgodne ze specyfikacją Wartości odwołania metody uwierzytelniania.
Podczas logowania bez uwierzytelniania wieloskładnikowego (na przykład przy użyciu tylko hasła):
Parametr
amr
mapwd
wartość:Odmowa dostępu:
Alternatywnie logowanie przy użyciu protokołu OTP za Identitypomocą polecenia :
Dostosowywanie parametrów OIDC i OAuth
Opcja procedury obsługi AdditionalAuthorizationParameters
uwierzytelniania OAuth i OIDC umożliwia dostosowanie parametrów komunikatów autoryzacji, które są zwykle dołączane jako część ciągu zapytania przekierowania:
builder.Services.AddAuthentication().AddOpenIdConnect(options =>
{
options.AdditionalAuthorizationParameters.Add("prompt", "login");
options.AdditionalAuthorizationParameters.Add("audience", "https://api.example.com");
});
Dodatkowe zasoby
Autor: Damien Bowden
Uwierzytelnianie wieloskładnikowe (MFA) to proces, w którym użytkownik jest proszony podczas logowania w celu uzyskania dodatkowych form identyfikacji. Ten monit może być wprowadzenie kodu z telefonu komórkowego, użycie klucza FIDO2 lub dostarczenie skanowania odciskiem palca. Jeśli potrzebujesz drugiej formy uwierzytelniania, zabezpieczenia są ulepszone. Dodatkowy czynnik nie jest łatwo uzyskiwany ani duplikowany przez cyberatakę.
W tym artykule opisano następujące obszary:
- Co to jest uwierzytelnianie wieloskładnikowe i jakie przepływy uwierzytelniania wieloskładnikowego są zalecane
- Konfigurowanie uwierzytelniania wieloskładnikowego dla stron administracyjnych przy użyciu platformy ASP.NET Core Identity
- Wysyłanie wymagania logowania wieloskładnikowego do serwera OpenID Connect
- Wymuszanie ASP.NET klienta OpenID Connect w celu wymagania uwierzytelniania wieloskładnikowego
Uwierzytelnianie wieloskładnikowe, 2FA
Uwierzytelnianie wieloskładnikowe wymaga co najmniej dwóch typów dowodu dla identity czegoś podobnego do posiadanego, posiadanego lub biometrycznego sprawdzania poprawności w celu uwierzytelnienia użytkownika.
Uwierzytelnianie dwuskładnikowe (2FA) jest jak podzbiór uwierzytelniania wieloskładnikowego, ale różnica polega na tym, że uwierzytelnianie wieloskładnikowe może wymagać co najmniej dwóch czynników, aby udowodnić wartość identity.
2FA jest domyślnie obsługiwane w przypadku korzystania z ASP.NET Core Identity. Aby włączyć lub wyłączyć uwierzytelnianie 2FA dla określonego użytkownika, ustaw IdentityUser<TKey>.TwoFactorEnabled właściwość . Domyślny interfejs użytkownika platformy ASP.NET Core Identity zawiera strony służące do konfigurowania uwierzytelniania 2FA.
MFA TOTP (algorytm haseł jednorazowych oparty na czasie)
Uwierzytelnianie wieloskładnikowe przy użyciu protokołu TOTP jest domyślnie obsługiwane w przypadku korzystania z usługi ASP.NET Core Identity. Takie podejście może być używane razem z dowolną zgodną aplikacją wystawcy uwierzytelniania, w tym:
- Microsoft Authenticator
- Google Authenticator
Aby uzyskać szczegółowe informacje o implementacji, zobacz Włączanie generowania kodu QR dla aplikacji wystawcy uwierzytelniania TOTP w programie ASP.NET Core.
Aby wyłączyć obsługę protokołu MFA TOTP, skonfiguruj uwierzytelnianie przy użyciu AddIdentity zamiast AddDefaultIdentity. AddDefaultIdentity
wywołuje AddDefaultTokenProviders wewnętrznie, co rejestruje wielu dostawców tokenów, w tym jednego dla uwierzytelniania wieloskładnikowego TOTP. Aby zarejestrować tylko określonych dostawców tokenów, wywołaj AddTokenProvider dla każdego wymaganego dostawcy. Aby uzyskać więcej informacji na temat dostępnych dostawców tokenów, zobacz źródło AddDefaultTokenProviders w witrynie GitHub.
Hasła uwierzytelniania wieloskładnikowego/FIDO2 lub bez hasła
Klucz dostępu/FIDO2 jest obecnie:
- Najbezpieczniejszy sposób osiągnięcia uwierzytelniania wieloskładnikowego.
- Uwierzytelnianie wieloskładnikowe chroniące przed atakami wyłudzającymi informacje. (Oprócz uwierzytelniania certyfikatów i systemu Windows dla firm)
Obecnie ASP.NET Core nie obsługuje bezpośrednio kluczy dostępu/FIDO2. W przypadku przepływów MFA lub bez hasła można używać kluczy dostępu/FIDO2.
Identyfikator Entra firmy Microsoft zapewnia obsługę przepływów passkeys/FIDO2 i bez hasła. Aby uzyskać więcej informacji, zobacz Opcje uwierzytelniania bez hasła.
Inne formy uwierzytelniania wieloskładnikowego bez hasła nie są chronione przed wyłudzaniem informacji.
Wiadomość SMS dotycząca uwierzytelniania wieloskładnikowego
Uwierzytelnianie wieloskładnikowe z programem SMS zwiększa bezpieczeństwo w porównaniu z uwierzytelnianiem przy użyciu hasła (pojedynczy czynnik). Jednak używanie wiadomości SMS jako drugiego czynnika nie jest już zalecane. Dla tego typu implementacji istnieje zbyt wiele znanych wektorów ataków.
Konfigurowanie uwierzytelniania wieloskładnikowego dla stron administracyjnych przy użyciu platformy ASP.NET Core Identity
Uwierzytelnianie wieloskładnikowe można wymusić na użytkownikach dostęp do poufnych stron w aplikacji ASP.NET Core Identity . Może to być przydatne w przypadku aplikacji, w których istnieją różne poziomy dostępu dla różnych tożsamości. Na przykład użytkownicy mogą wyświetlać dane profilu przy użyciu logowania przy użyciu hasła, ale administrator musi użyć uwierzytelniania wieloskładnikowego w celu uzyskania dostępu do stron administracyjnych.
Rozszerzanie nazwy logowania przy użyciu oświadczenia uwierzytelniania wieloskładnikowego
Kod demonstracyjny jest konfigurowany przy użyciu platformy ASP.NET Core z usługami Identity i Razor Pages. Metoda AddIdentity
jest używana zamiast AddDefaultIdentity
jednej, więc implementacja IUserClaimsPrincipalFactory
może służyć do dodawania oświadczeń do identity po pomyślnym zalogowaniu.
Ostrzeżenie
W tym artykule przedstawiono użycie parametry połączenia. W przypadku lokalnej bazy danych użytkownik nie musi być uwierzytelniany, ale w środowisku produkcyjnym parametry połączenia czasami zawiera hasło do uwierzytelniania. Poświadczenie hasła właściciela zasobu (ROPC) jest zagrożeniem bezpieczeństwa, którego należy unikać w produkcyjnych bazach danych. Aplikacje produkcyjne powinny korzystać z najbezpieczniejszego dostępnego przepływu uwierzytelniania. Aby uzyskać więcej informacji na temat uwierzytelniania aplikacji wdrożonych w środowiskach testowych lub produkcyjnych, zobacz Bezpieczne przepływy uwierzytelniania.
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();
Klasa AdditionalUserClaimsPrincipalFactory
dodaje amr
oświadczenie do oświadczenia użytkownika tylko po pomyślnym zalogowaniu. Wartość oświadczenia jest odczytywana z bazy danych. Oświadczenie jest dodawane tutaj, ponieważ użytkownik powinien uzyskać dostęp tylko do wyższego widoku chronionego, jeśli identity użytkownik zalogował się przy użyciu uwierzytelniania wieloskładnikowego. Jeśli widok bazy danych jest odczytywany bezpośrednio z bazy danych zamiast korzystać z oświadczenia, można uzyskać dostęp do widoku bez uwierzytelniania wieloskładnikowego bezpośrednio po aktywowaniu uwierzytelniania wieloskładnikowego.
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 Ponieważ konfiguracja usługi zmieniła się w Startup
klasie, układy Identity muszą zostać zaktualizowane. Tworzenie szkieletu Identity stron w aplikacji. Zdefiniuj Identity/Account/Manage/_Layout.cshtml
układ w pliku.
@{
Layout = "/Pages/Shared/_Layout.cshtml";
}
Przypisz również układ dla wszystkich stron zarządzania na Identity stronach:
@{
Layout = "_Layout.cshtml";
}
Weryfikowanie wymagania uwierzytelniania wieloskładnikowego na stronie administracyjnej
Strona administracyjna Razor sprawdza, czy użytkownik zalogował się przy użyciu uwierzytelniania wieloskładnikowego. W metodzie OnGet
identity parametr jest używany do uzyskiwania dostępu do oświadczeń użytkownika. Oświadczenie amr
jest sprawdzane pod kątem wartości mfa
. identity Jeśli brakuje tego oświadczenia lub jest false
, strona przekierowuje do strony Włączanie uwierzytelniania wieloskładnikowego. Jest to możliwe, ponieważ użytkownik zalogował się już, ale bez uwierzytelniania wieloskładnikowego.
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();
}
}
}
Logika interfejsu użytkownika w celu przełączania informacji logowania użytkownika
Zasady autoryzacji zostały dodane podczas uruchamiania. Zasady wymagają amr
oświadczenia o wartości mfa
.
services.AddAuthorization(options =>
options.AddPolicy("TwoFactorEnabled",
x => x.RequireClaim("amr", "mfa")));
Te zasady można następnie użyć w _Layout
widoku, aby wyświetlić lub ukryć menu Administratora z ostrzeżeniem:
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@inject IAuthorizationService AuthorizationService
Jeśli użytkownik identity zalogował się przy użyciu uwierzytelniania wieloskładnikowego, menu Administratora jest wyświetlane bez ostrzeżenia etykietki narzędzia. Gdy użytkownik zalogował się bez uwierzytelniania wieloskładnikowego, zostanie wyświetlone menu Administrator (nie włączono) wraz z etykietkę narzędzia informującą użytkownika (wyjaśnienie ostrzeżenia).
@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>
}
}
Jeśli użytkownik zaloguje się bez uwierzytelniania wieloskładnikowego, zostanie wyświetlone ostrzeżenie:
Użytkownik jest przekierowywany do widoku włączania uwierzytelniania wieloskładnikowego po kliknięciu linku Administratora :
Wysyłanie wymagania logowania wieloskładnikowego do serwera OpenID Connect
Parametr acr_values
może służyć do przekazywania wymaganej mfa
wartości z klienta do serwera w żądaniu uwierzytelniania.
Uwaga
Aby acr_values
ten parametr działał, należy obsłużyć na serwerze OpenID Connect.
Klient OpenID Connect ASP.NET Core
Aplikacja kliencka OpenID Connect ASP.NET Core Razor Pages używa AddOpenIdConnect
metody logowania do serwera OpenID Connect. Parametr acr_values
jest ustawiany z wartością mfa
i wysyłany z żądaniem uwierzytelniania. Element służy do dodawania OpenIdConnectEvents
tego elementu.
Aby uzyskać zalecane acr_values
wartości parametrów, zobacz Wartości referencyjne metody uwierzytelniania.
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);
}
};
});
Przykładowy serwer OpenID Connect Duende IdentityServer z ASP.NET Core Identity
Na serwerze OpenID Connect, który jest implementowany przy użyciu ASP.NET Core Identity ze stronami Razor , zostanie utworzona nowa strona o nazwie ErrorEnable2FA.cshtml
. Widok:
- Wyświetla, czy Identity element pochodzi z aplikacji wymagającej uwierzytelniania wieloskładnikowego, ale użytkownik nie aktywował go w programie Identity.
- Informuje użytkownika i dodaje link, aby to aktywować.
@{
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>
W metodzie implementacja _interaction
interfejsu Login
IIdentityServerInteractionService
jest używana do uzyskiwania dostępu do parametrów żądania OpenID Connect. Dostęp acr_values
do parametru AcrValues
jest uzyskiwany przy użyciu właściwości . Po wysłaniu tego polecenia przez klienta z mfa
zestawem można to sprawdzić.
Jeśli uwierzytelnianie wieloskładnikowe jest wymagane, a użytkownik w aplikacji ASP.NET Core Identity ma włączoną uwierzytelnianie wieloskładnikowe, logowanie będzie kontynuowane. Gdy użytkownik nie ma włączonej uwierzytelniania wieloskładnikowego, użytkownik jest przekierowywany do widoku ErrorEnable2FA.cshtml
niestandardowego . Następnie ASP.NET Core Identity loguje użytkownika.
Magazyn Fido2Store służy do sprawdzania, czy użytkownik aktywował uwierzytelnianie wieloskładnikowe przy użyciu niestandardowego dostawcy tokenów FIDO2.
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();
}
Jeśli użytkownik jest już zalogowany, aplikacja kliencka:
- Nadal sprawdza poprawność
amr
oświadczenia. - Można skonfigurować uwierzytelnianie wieloskładnikowe za pomocą linku do widoku ASP.NET Core Identity .
Wymuszanie ASP.NET klienta OpenID Connect w celu wymagania uwierzytelniania wieloskładnikowego
W tym przykładzie pokazano, jak aplikacja ASP.NET Core Razor Page, która używa interfejsu OpenID Connect do logowania, może wymagać uwierzytelnienia użytkowników przy użyciu uwierzytelniania wieloskładnikowego.
Aby zweryfikować wymaganie uwierzytelniania wieloskładnikowego, IAuthorizationRequirement
zostanie utworzone wymaganie. Zostanie to dodane do stron przy użyciu zasad wymagających uwierzytelniania wieloskładnikowego.
using Microsoft.AspNetCore.Authorization;
namespace AspNetCoreRequireMfaOidc;
public class RequireMfa : IAuthorizationRequirement{}
Zaimplementowano AuthorizationHandler
element , który będzie używał amr
oświadczenia i sprawdzał wartość mfa
. Element amr
jest zwracany w elemencie id_token
pomyślnego uwierzytelniania i może mieć wiele różnych wartości zdefiniowanych w specyfikacji Wartości referencyjne metody uwierzytelniania.
Zwrócona wartość zależy od sposobu identity uwierzytelnienia i implementacji serwera OpenID Connect.
RequireMfa
Używa AuthorizationHandler
wymagania i weryfikuje amr
oświadczenie. Serwer OpenID Connect można zaimplementować przy użyciu serwera Duende Identity z programem ASP.NET Core Identity. Gdy użytkownik loguje się przy użyciu protokołu TOTP, amr
oświadczenie jest zwracane z wartością uwierzytelniania wieloskładnikowego. Jeśli używasz innej implementacji serwera OpenID Connect lub innego typu uwierzytelniania wieloskładnikowego, amr
oświadczenie będzie lub może mieć inną wartość. Aby można było również zaakceptować ten kod, należy go rozszerzyć.
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;
}
}
W pliku AddOpenIdConnect
programu metoda jest używana jako domyślny schemat wyzwania. Procedura obsługi autoryzacji używana do sprawdzania amr
oświadczenia jest dodawana do kontenera Inversion of Control. Następnie zostanie utworzona zasada, która dodaje RequireMfa
wymaganie.
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();
Te zasady są następnie używane na stronie zgodnie z Razor wymaganiami. Zasady można również dodać globalnie dla całej aplikacji.
[Authorize(Policy= "RequireMfa")]
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
Jeśli użytkownik uwierzytelnia się bez uwierzytelniania wieloskładnikowego, amr
oświadczenie prawdopodobnie będzie miało pwd
wartość. Żądanie nie będzie autoryzowane w celu uzyskania dostępu do strony. Przy użyciu wartości domyślnych użytkownik zostanie przekierowany do strony Account/AccessDenied . To zachowanie można zmienić lub zaimplementować własną logikę niestandardową tutaj. W tym przykładzie zostanie dodany link, aby prawidłowy użytkownik mógł skonfigurować uwierzytelnianie wieloskładnikowe dla swojego konta.
@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>
Teraz tylko użytkownicy uwierzytelnieni za pomocą uwierzytelniania wieloskładnikowego mogą uzyskiwać dostęp do strony lub witryny internetowej. Jeśli są używane różne typy uwierzytelniania wieloskładnikowego lub jeśli uwierzytelnianie 2FA jest w porządku, amr
oświadczenie będzie miało różne wartości i musi zostać prawidłowo przetworzone. Różne serwery OpenID Connect zwracają również różne wartości dla tego oświadczenia i mogą nie być zgodne ze specyfikacją Wartości odwołania metody uwierzytelniania.
Podczas logowania bez uwierzytelniania wieloskładnikowego (na przykład przy użyciu tylko hasła):
Parametr
amr
mapwd
wartość:Odmowa dostępu:
Alternatywnie logowanie przy użyciu protokołu OTP za Identitypomocą polecenia :
Dodatkowe zasoby
Autor: Damien Bowden
Uwierzytelnianie wieloskładnikowe (MFA) to proces, w którym użytkownik jest proszony podczas logowania w celu uzyskania dodatkowych form identyfikacji. Ten monit może być wprowadzenie kodu z telefonu komórkowego, użycie klucza FIDO2 lub dostarczenie skanowania odciskiem palca. Jeśli potrzebujesz drugiej formy uwierzytelniania, zabezpieczenia są ulepszone. Dodatkowy czynnik nie jest łatwo uzyskiwany ani duplikowany przez cyberatakę.
W tym artykule opisano następujące obszary:
- Co to jest uwierzytelnianie wieloskładnikowe i jakie przepływy uwierzytelniania wieloskładnikowego są zalecane
- Konfigurowanie uwierzytelniania wieloskładnikowego dla stron administracyjnych przy użyciu platformy ASP.NET Core Identity
- Wysyłanie wymagania logowania wieloskładnikowego do serwera OpenID Connect
- Wymuszanie ASP.NET klienta OpenID Connect w celu wymagania uwierzytelniania wieloskładnikowego
Uwierzytelnianie wieloskładnikowe, 2FA
Uwierzytelnianie wieloskładnikowe wymaga co najmniej dwóch typów dowodu dla identity czegoś podobnego do posiadanego, posiadanego lub biometrycznego sprawdzania poprawności w celu uwierzytelnienia użytkownika.
Uwierzytelnianie dwuskładnikowe (2FA) jest jak podzbiór uwierzytelniania wieloskładnikowego, ale różnica polega na tym, że uwierzytelnianie wieloskładnikowe może wymagać co najmniej dwóch czynników, aby udowodnić wartość identity.
MFA TOTP (algorytm haseł jednorazowych oparty na czasie)
Uwierzytelnianie wieloskładnikowe korzystające z protokołu TOTP jest obsługiwaną implementacją przy użyciu ASP.NET Core Identity. Może to być używane razem z dowolną zgodną aplikacją wystawcy uwierzytelniania, w tym:
- Aplikacja Microsoft Authenticator
- Aplikacja Google Authenticator
Aby uzyskać szczegółowe informacje o implementacji, zobacz następujący link:
Włączanie generowania kodów QR dla aplikacji uwierzytelniania TOTP na platformie ASP.NET Core
Hasła uwierzytelniania wieloskładnikowego/FIDO2 lub bez hasła
Klucz dostępu/FIDO2 jest obecnie:
- Najbezpieczniejszy sposób osiągnięcia uwierzytelniania wieloskładnikowego.
- Uwierzytelnianie wieloskładnikowe chroniące przed atakami wyłudzającymi informacje. (Oprócz uwierzytelniania certyfikatów i systemu Windows dla firm)
Obecnie ASP.NET Core nie obsługuje bezpośrednio kluczy dostępu/FIDO2. W przypadku przepływów MFA lub bez hasła można używać kluczy dostępu/FIDO2.
Identyfikator Entra firmy Microsoft zapewnia obsługę przepływów passkeys/FIDO2 i bez hasła. Aby uzyskać więcej informacji, zobacz Opcje uwierzytelniania bez hasła.
Inne formy uwierzytelniania wieloskładnikowego bez hasła nie są chronione przed wyłudzaniem informacji.
Wiadomość SMS dotycząca uwierzytelniania wieloskładnikowego
Uwierzytelnianie wieloskładnikowe z programem SMS zwiększa bezpieczeństwo w porównaniu z uwierzytelnianiem przy użyciu hasła (pojedynczy czynnik). Jednak używanie wiadomości SMS jako drugiego czynnika nie jest już zalecane. Dla tego typu implementacji istnieje zbyt wiele znanych wektorów ataków.
Konfigurowanie uwierzytelniania wieloskładnikowego dla stron administracyjnych przy użyciu platformy ASP.NET Core Identity
Uwierzytelnianie wieloskładnikowe można wymusić na użytkownikach dostęp do poufnych stron w aplikacji ASP.NET Core Identity . Może to być przydatne w przypadku aplikacji, w których istnieją różne poziomy dostępu dla różnych tożsamości. Na przykład użytkownicy mogą wyświetlać dane profilu przy użyciu logowania przy użyciu hasła, ale administrator musi użyć uwierzytelniania wieloskładnikowego w celu uzyskania dostępu do stron administracyjnych.
Rozszerzanie nazwy logowania przy użyciu oświadczenia uwierzytelniania wieloskładnikowego
Kod demonstracyjny jest konfigurowany przy użyciu platformy ASP.NET Core z usługami Identity i Razor Pages. Metoda AddIdentity
jest używana zamiast AddDefaultIdentity
jednej, więc implementacja IUserClaimsPrincipalFactory
może służyć do dodawania oświadczeń do identity po pomyślnym zalogowaniu.
Ostrzeżenie
W tym artykule przedstawiono użycie parametry połączenia. W przypadku lokalnej bazy danych użytkownik nie musi być uwierzytelniany, ale w środowisku produkcyjnym parametry połączenia czasami zawiera hasło do uwierzytelniania. Poświadczenie hasła właściciela zasobu (ROPC) jest zagrożeniem bezpieczeństwa, którego należy unikać w produkcyjnych bazach danych. Aplikacje produkcyjne powinny korzystać z najbezpieczniejszego dostępnego przepływu uwierzytelniania. Aby uzyskać więcej informacji na temat uwierzytelniania aplikacji wdrożonych w środowiskach testowych lub produkcyjnych, zobacz Bezpieczne przepływy uwierzytelniania.
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();
}
Klasa AdditionalUserClaimsPrincipalFactory
dodaje amr
oświadczenie do oświadczenia użytkownika tylko po pomyślnym zalogowaniu. Wartość oświadczenia jest odczytywana z bazy danych. Oświadczenie jest dodawane tutaj, ponieważ użytkownik powinien uzyskać dostęp tylko do wyższego widoku chronionego, jeśli identity użytkownik zalogował się przy użyciu uwierzytelniania wieloskładnikowego. Jeśli widok bazy danych jest odczytywany bezpośrednio z bazy danych zamiast korzystać z oświadczenia, można uzyskać dostęp do widoku bez uwierzytelniania wieloskładnikowego bezpośrednio po aktywowaniu uwierzytelniania wieloskładnikowego.
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 Ponieważ konfiguracja usługi zmieniła się w Startup
klasie, układy Identity muszą zostać zaktualizowane. Tworzenie szkieletu Identity stron w aplikacji. Zdefiniuj Identity/Account/Manage/_Layout.cshtml
układ w pliku.
@{
Layout = "/Pages/Shared/_Layout.cshtml";
}
Przypisz również układ dla wszystkich stron zarządzania na Identity stronach:
@{
Layout = "_Layout.cshtml";
}
Weryfikowanie wymagania uwierzytelniania wieloskładnikowego na stronie administracyjnej
Strona administracyjna Razor sprawdza, czy użytkownik zalogował się przy użyciu uwierzytelniania wieloskładnikowego. W metodzie OnGet
identity parametr jest używany do uzyskiwania dostępu do oświadczeń użytkownika. Oświadczenie amr
jest sprawdzane pod kątem wartości mfa
. identity Jeśli brakuje tego oświadczenia lub jest false
, strona przekierowuje do strony Włączanie uwierzytelniania wieloskładnikowego. Jest to możliwe, ponieważ użytkownik zalogował się już, ale bez uwierzytelniania wieloskładnikowego.
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();
}
}
}
Logika interfejsu użytkownika w celu przełączania informacji logowania użytkownika
Zasady autoryzacji zostały dodane w pliku programu. Zasady wymagają amr
oświadczenia o wartości mfa
.
builder.Services.AddAuthorization(options =>
options.AddPolicy("TwoFactorEnabled",
x => x.RequireClaim("amr", "mfa")));
Te zasady można następnie użyć w _Layout
widoku, aby wyświetlić lub ukryć menu Administratora z ostrzeżeniem:
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@inject IAuthorizationService AuthorizationService
Jeśli użytkownik identity zalogował się przy użyciu uwierzytelniania wieloskładnikowego, menu Administratora jest wyświetlane bez ostrzeżenia etykietki narzędzia. Gdy użytkownik zalogował się bez uwierzytelniania wieloskładnikowego, zostanie wyświetlone menu Administrator (nie włączono) wraz z etykietkę narzędzia informującą użytkownika (wyjaśnienie ostrzeżenia).
@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>
}
}
Jeśli użytkownik zaloguje się bez uwierzytelniania wieloskładnikowego, zostanie wyświetlone ostrzeżenie:
Użytkownik jest przekierowywany do widoku włączania uwierzytelniania wieloskładnikowego po kliknięciu linku Administratora :
Wysyłanie wymagania logowania wieloskładnikowego do serwera OpenID Connect
Parametr acr_values
może służyć do przekazywania wymaganej mfa
wartości z klienta do serwera w żądaniu uwierzytelniania.
Uwaga
Aby acr_values
ten parametr działał, należy obsłużyć na serwerze OpenID Connect.
Klient OpenID Connect ASP.NET Core
Aplikacja kliencka OpenID Connect ASP.NET Core Razor Pages używa AddOpenIdConnect
metody logowania do serwera OpenID Connect. Parametr acr_values
jest ustawiany z wartością mfa
i wysyłany z żądaniem uwierzytelniania. Element służy do dodawania OpenIdConnectEvents
tego elementu.
Aby uzyskać zalecane acr_values
wartości parametrów, zobacz Wartości referencyjne metody uwierzytelniania.
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);
}
};
});
Przykładowy serwer OpenID Connect IdentityServer 4 z ASP.NET Core Identity
Na serwerze OpenID Connect, który jest implementowany przy użyciu ASP.NET Core Identity z widokami MVC, zostanie utworzony nowy widok o nazwie ErrorEnable2FA.cshtml
. Widok:
- Wyświetla, czy Identity element pochodzi z aplikacji wymagającej uwierzytelniania wieloskładnikowego, ale użytkownik nie aktywował go w programie Identity.
- Informuje użytkownika i dodaje link, aby to aktywować.
@{
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>
W metodzie implementacja _interaction
interfejsu Login
IIdentityServerInteractionService
jest używana do uzyskiwania dostępu do parametrów żądania OpenID Connect. Dostęp acr_values
do parametru AcrValues
jest uzyskiwany przy użyciu właściwości . Po wysłaniu tego polecenia przez klienta z mfa
zestawem można to sprawdzić.
Jeśli uwierzytelnianie wieloskładnikowe jest wymagane, a użytkownik w aplikacji ASP.NET Core Identity ma włączoną uwierzytelnianie wieloskładnikowe, logowanie będzie kontynuowane. Gdy użytkownik nie ma włączonej uwierzytelniania wieloskładnikowego, użytkownik jest przekierowywany do widoku ErrorEnable2FA.cshtml
niestandardowego . Następnie ASP.NET Core Identity loguje użytkownika.
//
// 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
Metoda ExternalLoginCallback
działa podobnie jak nazwa logowania lokalnego Identity . Właściwość AcrValues
jest sprawdzana pod kątem mfa
wartości. mfa
Jeśli wartość jest obecna, uwierzytelnianie wieloskładnikowe jest wymuszane przed ukończeniem logowania (na przykład przekierowanie do ErrorEnable2FA
widoku).
//
// 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
Jeśli użytkownik jest już zalogowany, aplikacja kliencka:
- Nadal sprawdza poprawność
amr
oświadczenia. - Można skonfigurować uwierzytelnianie wieloskładnikowe za pomocą linku do widoku ASP.NET Core Identity .
Wymuszanie ASP.NET klienta OpenID Connect w celu wymagania uwierzytelniania wieloskładnikowego
W tym przykładzie pokazano, jak aplikacja ASP.NET Core Razor Page, która używa interfejsu OpenID Connect do logowania, może wymagać uwierzytelnienia użytkowników przy użyciu uwierzytelniania wieloskładnikowego.
Aby zweryfikować wymaganie uwierzytelniania wieloskładnikowego, IAuthorizationRequirement
zostanie utworzone wymaganie. Zostanie to dodane do stron przy użyciu zasad wymagających uwierzytelniania wieloskładnikowego.
using Microsoft.AspNetCore.Authorization;
namespace AspNetCoreRequireMfaOidc
{
public class RequireMfa : IAuthorizationRequirement{}
}
Zaimplementowano AuthorizationHandler
element , który będzie używał amr
oświadczenia i sprawdzał wartość mfa
. Element amr
jest zwracany w elemencie id_token
pomyślnego uwierzytelniania i może mieć wiele różnych wartości zdefiniowanych w specyfikacji Wartości referencyjne metody uwierzytelniania.
Zwrócona wartość zależy od sposobu identity uwierzytelnienia i implementacji serwera OpenID Connect.
RequireMfa
Używa AuthorizationHandler
wymagania i weryfikuje amr
oświadczenie. Serwer OpenID Connect można zaimplementować przy użyciu serwera IdentityServer4 z ASP.NET Core Identity. Gdy użytkownik loguje się przy użyciu protokołu TOTP, amr
oświadczenie jest zwracane z wartością uwierzytelniania wieloskładnikowego. Jeśli używasz innej implementacji serwera OpenID Connect lub innego typu uwierzytelniania wieloskładnikowego, amr
oświadczenie będzie lub może mieć inną wartość. Aby można było również zaakceptować ten kod, należy go rozszerzyć.
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;
}
}
W metodzie Startup.ConfigureServices
AddOpenIdConnect
metoda jest używana jako domyślny schemat wyzwania. Procedura obsługi autoryzacji używana do sprawdzania amr
oświadczenia jest dodawana do kontenera Inversion of Control. Następnie zostanie utworzona zasada, która dodaje RequireMfa
wymaganie.
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();
}
Te zasady są następnie używane na stronie zgodnie z Razor wymaganiami. Zasady można również dodać globalnie dla całej aplikacji.
[Authorize(Policy= "RequireMfa")]
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
Jeśli użytkownik uwierzytelnia się bez uwierzytelniania wieloskładnikowego, amr
oświadczenie prawdopodobnie będzie miało pwd
wartość. Żądanie nie będzie autoryzowane w celu uzyskania dostępu do strony. Przy użyciu wartości domyślnych użytkownik zostanie przekierowany do strony Account/AccessDenied . To zachowanie można zmienić lub zaimplementować własną logikę niestandardową tutaj. W tym przykładzie zostanie dodany link, aby prawidłowy użytkownik mógł skonfigurować uwierzytelnianie wieloskładnikowe dla swojego konta.
@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>
Teraz tylko użytkownicy uwierzytelnieni za pomocą uwierzytelniania wieloskładnikowego mogą uzyskiwać dostęp do strony lub witryny internetowej. Jeśli są używane różne typy uwierzytelniania wieloskładnikowego lub jeśli uwierzytelnianie 2FA jest w porządku, amr
oświadczenie będzie miało różne wartości i musi zostać prawidłowo przetworzone. Różne serwery OpenID Connect zwracają również różne wartości dla tego oświadczenia i mogą nie być zgodne ze specyfikacją Wartości odwołania metody uwierzytelniania.
Podczas logowania bez uwierzytelniania wieloskładnikowego (na przykład przy użyciu tylko hasła):
Parametr
amr
mapwd
wartość:Odmowa dostępu:
Alternatywnie logowanie przy użyciu protokołu OTP za Identitypomocą polecenia :