Autenticazione a più fattori in ASP.NET Core
Nota
Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 8 di questo articolo.
Avviso
Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere Criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 8 di questo articolo.
Importante
Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.
Per la versione corrente, vedere la versione .NET 8 di questo articolo.
L'autenticazione a più fattori (MFA) è un processo in cui un utente viene richiesto durante un evento di accesso per ulteriori forme di identificazione. Questo prompt potrebbe essere quello di immettere un codice da un cellulare, usare un tasto FIDO2 o per fornire un'analisi delle impronte digitali. Quando è necessaria una seconda forma di autenticazione, la sicurezza viene migliorata. Il fattore aggiuntivo non è facilmente ottenuto o duplicato da un cyberattacker.
Questo articolo illustra le aree seguenti:
- Che cos'è MFA e quali flussi MFA sono consigliati
- Configurare MFA per le pagine di amministrazione usando ASP.NET Core Identity
- Inviare il requisito di accesso MFA al server OpenID Connect
- Forzare ASP.NET client OpenID Connect core per richiedere l'autenticazione a più fattori
MFA, 2FA
L'autenticazione a più fattori richiede almeno due o più tipi di prova per un identity elemento simile a quello che si conosce, un elemento che si possiede o la convalida biometrica per l'autenticazione dell'utente.
L'autenticazione a due fattori (2FA) è simile a un subset di MFA, ma la differenza consiste nel fatto che l'autenticazione a più fattori può richiedere due o più fattori per dimostrare .identity
2FA è supportato per impostazione predefinita quando si usa ASP.NET Core Identity. Per abilitare o disabilitare 2FA per un utente specifico, impostare la IdentityUser<TKey>.TwoFactorEnabled proprietà . L'interfaccia utente Identity predefinita di base ASP.NET include pagine per la configurazione di 2FA.
MFA TOTP (algoritmo password monouso basato sul tempo)
L'autenticazione a più fattori tramite TOTP è supportata per impostazione predefinita quando si usa ASP.NET Core Identity. Questo approccio può essere usato insieme a qualsiasi app di autenticazione conforme, tra cui:
- Microsoft Authenticator
- Google Authenticator
Per informazioni dettagliate sull'implementazione, vedere Abilitare la generazione di codice a matrice per le app di autenticazione TOTP in ASP.NET Core.
Per disabilitare il supporto per MFA TOTP, configurare l'autenticazione usando AddIdentity anziché AddDefaultIdentity. AddDefaultIdentity
chiama AddDefaultTokenProviders internamente, che registra più provider di token, tra cui uno per MFA TOTP. Per registrare solo provider di token specifici, chiamare AddTokenProvider per ogni provider necessario. Per altre informazioni sui provider di token disponibili, vedere l'origine AddDefaultTokenProviders in GitHub.
Passkey MFA/FIDO2 o senza password
passkeys/FIDO2 è attualmente:
- Il modo più sicuro per ottenere l'autenticazione a più fattori.
- MFA che protegge dagli attacchi di phishing. (Oltre all'autenticazione del certificato e a Windows per le aziende)
Attualmente, ASP.NET Core non supporta direttamente passkeys/FIDO2. Passkeys/FIDO2 può essere usato per i flussi MFA o senza password.
Microsoft Entra ID fornisce il supporto per i flussi passkeys/FIDO2 e senza password. Per altre informazioni, vedere Opzioni di autenticazione senza password.
Altre forme di autenticazione a più fattori senza password non proteggono o meno dal phishing.
MFA SMS
L'autenticazione a più fattori con SMS aumenta notevolmente la sicurezza rispetto all'autenticazione della password (fattore singolo). Tuttavia, l'uso di SMS come secondo fattore non è più consigliato. Per questo tipo di implementazione esistono troppi vettori di attacco noti.
Configurare MFA per le pagine di amministrazione usando ASP.NET Core Identity
L'autenticazione a più fattori potrebbe essere costretta agli utenti ad accedere alle pagine sensibili all'interno di un'app ASP.NET Core Identity . Ciò può essere utile per le app in cui esistono diversi livelli di accesso per le diverse identità. Ad esempio, gli utenti potrebbero essere in grado di visualizzare i dati del profilo usando un account di accesso con password, ma un amministratore deve usare l'autenticazione a più fattori per accedere alle pagine amministrative.
Estendere l'account di accesso con un'attestazione MFA
Il codice demo viene configurato usando ASP.NET Core con Identity e Razor Pages. Il AddIdentity
metodo viene usato invece di AddDefaultIdentity
uno, quindi è possibile usare un'implementazione IUserClaimsPrincipalFactory
per aggiungere attestazioni a identity dopo un account di accesso riuscito.
Avviso
Questo articolo illustra l'uso di stringa di connessione. Con un database locale l'utente non deve essere autenticato, ma nell'ambiente di produzione stringa di connessione talvolta include una password per l'autenticazione. Una credenziale della password del proprietario della risorsa (ROPC) è un rischio per la sicurezza che deve essere evitato nei database di produzione. Le app di produzione devono usare il flusso di autenticazione più sicuro disponibile. Per altre informazioni sull'autenticazione per le app distribuite in ambienti di test o di produzione, vedere Proteggere i flussi di autenticazione.
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();
La AdditionalUserClaimsPrincipalFactory
classe aggiunge l'attestazione amr
alle attestazioni utente solo dopo un accesso riuscito. Il valore dell'attestazione viene letto dal database. L'attestazione viene aggiunta qui perché l'utente deve accedere alla visualizzazione protetta superiore solo se ha eseguito l'accesso identity con MFA. Se la vista del database viene letta direttamente dal database anziché usare l'attestazione, è possibile accedere alla vista senza MFA direttamente dopo l'attivazione dell'autenticazione a più fattori.
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;
}
}
}
Poiché l'installazione del Identity servizio è stata modificata nella Startup
classe , è necessario aggiornare i layout dell'oggetto Identity . Eseguire lo scaffolding delle Identity pagine nell'app. Definire il layout nel Identity/Account/Manage/_Layout.cshtml
file.
@{
Layout = "/Pages/Shared/_Layout.cshtml";
}
Assegnare anche il layout per tutte le pagine di gestione dalle Identity pagine:
@{
Layout = "_Layout.cshtml";
}
Convalidare il requisito MFA nella pagina di amministrazione
La pagina di amministrazione Razor verifica che l'utente abbia eseguito l'accesso tramite MFA. OnGet
Nel metodo viene identity usato per accedere alle attestazioni utente. L'attestazione amr
viene verificata per il valore mfa
. Se manca identity questa attestazione o è false
, la pagina reindirizza alla pagina Abilita MFA. Ciò è possibile perché l'utente ha già eseguito l'accesso, ma senza MFA.
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();
}
}
}
Logica dell'interfaccia utente per attivare o disattivare le informazioni di accesso utente
All'avvio è stato aggiunto un criterio di autorizzazione. Il criterio richiede l'attestazione amr
con il valore mfa
.
services.AddAuthorization(options =>
options.AddPolicy("TwoFactorEnabled",
x => x.RequireClaim("amr", "mfa")));
Questo criterio può quindi essere usato nella _Layout
visualizzazione per visualizzare o nascondere il menu Admin con l'avviso:
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@inject IAuthorizationService AuthorizationService
Se l'oggetto ha eseguito l'accesso identity tramite MFA, il menu Admin viene visualizzato senza l'avviso della descrizione comando. Quando l'utente ha eseguito l'accesso senza MFA, il menu Admin (Not Enabled) viene visualizzato insieme alla descrizione comando che informa l'utente (spiegando l'avviso).
@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>
}
}
Se l'utente accede senza MFA, viene visualizzato l'avviso:
L'utente viene reindirizzato alla visualizzazione di abilitazione dell'autenticazione a più fattori quando si fa clic sul collegamento Amministratore :
Inviare il requisito di accesso MFA al server OpenID Connect
Il acr_values
parametro può essere usato per passare il mfa
valore richiesto dal client al server in una richiesta di autenticazione.
Nota
Il acr_values
parametro deve essere gestito nel server OpenID Connect per il funzionamento.
Client OpenID Connect ASP.NET Core
L'app client OpenID Connect di ASP.NET Core Razor Pages usa il AddOpenIdConnect
metodo per accedere al server OpenID Connect. Il acr_values
parametro viene impostato con il mfa
valore e inviato con la richiesta di autenticazione. L'oggetto OpenIdConnectEvents
viene utilizzato per aggiungerlo.
Per i valori dei parametri consigliati acr_values
, vedere Valori di riferimento del metodo di autenticazione.
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");
});
Esempio di server OpenID Connect Duende IdentityServer con ASP.NET Core Identity
Nel server OpenID Connect, implementato tramite ASP.NET Core Identity con Razor Pages, viene creata una nuova pagina denominata ErrorEnable2FA.cshtml
. Visualizzazione :
- Visualizza se proviene Identity da un'app che richiede l'autenticazione a più fattori, ma l'utente non ha attivato questo valore in Identity.
- Informa l'utente e aggiunge un collegamento per attivarlo.
@{
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>
Login
Nel metodo viene usata l'implementazione dell'interfaccia IIdentityServerInteractionService
_interaction
per accedere ai parametri della richiesta OpenID Connect. È acr_values
possibile accedere al parametro usando la AcrValues
proprietà . Quando il client lo ha inviato con mfa
set, è quindi possibile controllarne il contenuto.
Se è necessaria l'autenticazione a più fattori e l'utente in ASP.NET Core Identity ha abilitato MFA, l'account di accesso continua. Quando l'utente non dispone di MFA abilitata, l'utente viene reindirizzato alla visualizzazione ErrorEnable2FA.cshtml
personalizzata . Quindi ASP.NET Core Identity accede all'utente.
Fido2Store viene usato per verificare se l'utente ha attivato MFA usando un provider di token FIDO2 personalizzato.
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();
}
Se l'utente è già connesso, l'app client:
- Convalida comunque l'attestazione
amr
. - Può configurare l'autenticazione a più fattori con un collegamento alla visualizzazione ASP.NET Core Identity .
Forzare ASP.NET client OpenID Connect core per richiedere l'autenticazione a più fattori
Questo esempio mostra come un'app ASP.NET Core Razor Page, che usa OpenID Connect per accedere, può richiedere che gli utenti abbiano eseguito l'autenticazione tramite MFA.
Per convalidare il requisito MFA, viene creato un IAuthorizationRequirement
requisito. Questa operazione verrà aggiunta alle pagine usando un criterio che richiede l'autenticazione a più fattori.
using Microsoft.AspNetCore.Authorization;
namespace AspNetCoreRequireMfaOidc;
public class RequireMfa : IAuthorizationRequirement{}
Viene AuthorizationHandler
implementato che userà l'attestazione amr
e verificherà il valore mfa
. L'oggetto amr
id_token
viene restituito in di un'autenticazione riuscita e può avere molti valori diversi, come definito nella specifica Valori di riferimento del metodo di autenticazione.
Il valore restituito dipende dalla modalità identity di autenticazione e dall'implementazione del server OpenID Connect.
AuthorizationHandler
usa il RequireMfa
requisito e convalida l'attestazioneamr
. Il server OpenID Connect può essere implementato usando Duende Identity Server con ASP.NET Core Identity. Quando un utente accede con TOTP, l'attestazione amr
viene restituita con un valore MFA. Se si usa un'implementazione del server OpenID Connect diversa o un tipo MFA diverso, l'attestazione amr
o può avere un valore diverso. Il codice deve essere esteso anche per accettarlo.
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;
}
}
Nel file di programma il AddOpenIdConnect
metodo viene usato come schema di verifica predefinito. Il gestore di autorizzazione, usato per controllare l'attestazione amr
, viene aggiunto al contenitore Inversion of Control. Viene quindi creato un criterio che aggiunge il RequireMfa
requisito.
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();
Questo criterio viene quindi usato nella Razor pagina in base alle esigenze. I criteri possono essere aggiunti a livello globale anche per l'intera app.
[Authorize(Policy= "RequireMfa")]
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
Se l'utente esegue l'autenticazione senza MFA, l'attestazione amr
avrà probabilmente un pwd
valore. La richiesta non sarà autorizzata ad accedere alla pagina. Usando i valori predefiniti, l'utente verrà reindirizzato alla pagina Account/AccessDenied . Questo comportamento può essere modificato oppure è possibile implementare la propria logica personalizzata qui. In questo esempio viene aggiunto un collegamento in modo che l'utente valido possa configurare MFA per il proprio account.
@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>
Ora solo gli utenti che eseguono l'autenticazione con MFA possono accedere alla pagina o al sito Web. Se vengono usati diversi tipi di autenticazione a più fattori o se 2FA è corretto, l'attestazione amr
avrà valori diversi e deve essere elaborata correttamente. I diversi server OpenID Connect restituiscono anche valori diversi per questa attestazione e potrebbero non seguire la specifica Valori di riferimento del metodo di autenticazione.
Quando si esegue l'accesso senza autenticazione a più fattori(ad esempio, usando solo una password):
Ha
amr
ilpwd
valore :Accesso negato:
In alternativa, accedere usando OTP con Identity:
Personalizzazione dei parametri OIDC e OAuth
L'opzione gestori di autenticazione AdditionalAuthorizationParameters
OAuth e OIDC consente la personalizzazione dei parametri del messaggio di autorizzazione inclusi in genere come parte della stringa di query di reindirizzamento:
builder.Services.AddAuthentication().AddOpenIdConnect(options =>
{
options.AdditionalAuthorizationParameters.Add("prompt", "login");
options.AdditionalAuthorizationParameters.Add("audience", "https://api.example.com");
});
Risorse aggiuntive
L'autenticazione a più fattori (MFA) è un processo in cui un utente viene richiesto durante un evento di accesso per ulteriori forme di identificazione. Questo prompt potrebbe essere quello di immettere un codice da un cellulare, usare un tasto FIDO2 o per fornire un'analisi delle impronte digitali. Quando è necessaria una seconda forma di autenticazione, la sicurezza viene migliorata. Il fattore aggiuntivo non è facilmente ottenuto o duplicato da un cyberattacker.
Questo articolo illustra le aree seguenti:
- Che cos'è MFA e quali flussi MFA sono consigliati
- Configurare MFA per le pagine di amministrazione usando ASP.NET Core Identity
- Inviare il requisito di accesso MFA al server OpenID Connect
- Forzare ASP.NET client OpenID Connect core per richiedere l'autenticazione a più fattori
MFA, 2FA
L'autenticazione a più fattori richiede almeno due o più tipi di prova per un identity elemento simile a quello che si conosce, un elemento che si possiede o la convalida biometrica per l'autenticazione dell'utente.
L'autenticazione a due fattori (2FA) è simile a un subset di MFA, ma la differenza consiste nel fatto che l'autenticazione a più fattori può richiedere due o più fattori per dimostrare .identity
2FA è supportato per impostazione predefinita quando si usa ASP.NET Core Identity. Per abilitare o disabilitare 2FA per un utente specifico, impostare la IdentityUser<TKey>.TwoFactorEnabled proprietà . L'interfaccia utente Identity predefinita di base ASP.NET include pagine per la configurazione di 2FA.
MFA TOTP (algoritmo password monouso basato sul tempo)
L'autenticazione a più fattori tramite TOTP è supportata per impostazione predefinita quando si usa ASP.NET Core Identity. Questo approccio può essere usato insieme a qualsiasi app di autenticazione conforme, tra cui:
- Microsoft Authenticator
- Google Authenticator
Per informazioni dettagliate sull'implementazione, vedere Abilitare la generazione di codice a matrice per le app di autenticazione TOTP in ASP.NET Core.
Per disabilitare il supporto per MFA TOTP, configurare l'autenticazione usando AddIdentity anziché AddDefaultIdentity. AddDefaultIdentity
chiama AddDefaultTokenProviders internamente, che registra più provider di token, tra cui uno per MFA TOTP. Per registrare solo provider di token specifici, chiamare AddTokenProvider per ogni provider necessario. Per altre informazioni sui provider di token disponibili, vedere l'origine AddDefaultTokenProviders in GitHub.
Passkey MFA/FIDO2 o senza password
passkeys/FIDO2 è attualmente:
- Il modo più sicuro per ottenere l'autenticazione a più fattori.
- MFA che protegge dagli attacchi di phishing. (Oltre all'autenticazione del certificato e a Windows per le aziende)
Attualmente, ASP.NET Core non supporta direttamente passkeys/FIDO2. Passkeys/FIDO2 può essere usato per i flussi MFA o senza password.
Microsoft Entra ID fornisce il supporto per i flussi passkeys/FIDO2 e senza password. Per altre informazioni, vedere Opzioni di autenticazione senza password.
Altre forme di autenticazione a più fattori senza password non proteggono o meno dal phishing.
MFA SMS
L'autenticazione a più fattori con SMS aumenta notevolmente la sicurezza rispetto all'autenticazione della password (fattore singolo). Tuttavia, l'uso di SMS come secondo fattore non è più consigliato. Per questo tipo di implementazione esistono troppi vettori di attacco noti.
Configurare MFA per le pagine di amministrazione usando ASP.NET Core Identity
L'autenticazione a più fattori potrebbe essere costretta agli utenti ad accedere alle pagine sensibili all'interno di un'app ASP.NET Core Identity . Ciò può essere utile per le app in cui esistono diversi livelli di accesso per le diverse identità. Ad esempio, gli utenti potrebbero essere in grado di visualizzare i dati del profilo usando un account di accesso con password, ma un amministratore deve usare l'autenticazione a più fattori per accedere alle pagine amministrative.
Estendere l'account di accesso con un'attestazione MFA
Il codice demo viene configurato usando ASP.NET Core con Identity e Razor Pages. Il AddIdentity
metodo viene usato invece di AddDefaultIdentity
uno, quindi è possibile usare un'implementazione IUserClaimsPrincipalFactory
per aggiungere attestazioni a identity dopo un account di accesso riuscito.
Avviso
Questo articolo illustra l'uso di stringa di connessione. Con un database locale l'utente non deve essere autenticato, ma nell'ambiente di produzione stringa di connessione talvolta include una password per l'autenticazione. Una credenziale della password del proprietario della risorsa (ROPC) è un rischio per la sicurezza che deve essere evitato nei database di produzione. Le app di produzione devono usare il flusso di autenticazione più sicuro disponibile. Per altre informazioni sull'autenticazione per le app distribuite in ambienti di test o di produzione, vedere Proteggere i flussi di autenticazione.
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();
La AdditionalUserClaimsPrincipalFactory
classe aggiunge l'attestazione amr
alle attestazioni utente solo dopo un accesso riuscito. Il valore dell'attestazione viene letto dal database. L'attestazione viene aggiunta qui perché l'utente deve accedere alla visualizzazione protetta superiore solo se ha eseguito l'accesso identity con MFA. Se la vista del database viene letta direttamente dal database anziché usare l'attestazione, è possibile accedere alla vista senza MFA direttamente dopo l'attivazione dell'autenticazione a più fattori.
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;
}
}
}
Poiché l'installazione del Identity servizio è stata modificata nella Startup
classe , è necessario aggiornare i layout dell'oggetto Identity . Eseguire lo scaffolding delle Identity pagine nell'app. Definire il layout nel Identity/Account/Manage/_Layout.cshtml
file.
@{
Layout = "/Pages/Shared/_Layout.cshtml";
}
Assegnare anche il layout per tutte le pagine di gestione dalle Identity pagine:
@{
Layout = "_Layout.cshtml";
}
Convalidare il requisito MFA nella pagina di amministrazione
La pagina di amministrazione Razor verifica che l'utente abbia eseguito l'accesso tramite MFA. OnGet
Nel metodo viene identity usato per accedere alle attestazioni utente. L'attestazione amr
viene verificata per il valore mfa
. Se manca identity questa attestazione o è false
, la pagina reindirizza alla pagina Abilita MFA. Ciò è possibile perché l'utente ha già eseguito l'accesso, ma senza MFA.
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();
}
}
}
Logica dell'interfaccia utente per attivare o disattivare le informazioni di accesso utente
All'avvio è stato aggiunto un criterio di autorizzazione. Il criterio richiede l'attestazione amr
con il valore mfa
.
services.AddAuthorization(options =>
options.AddPolicy("TwoFactorEnabled",
x => x.RequireClaim("amr", "mfa")));
Questo criterio può quindi essere usato nella _Layout
visualizzazione per visualizzare o nascondere il menu Admin con l'avviso:
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@inject IAuthorizationService AuthorizationService
Se l'oggetto ha eseguito l'accesso identity tramite MFA, il menu Admin viene visualizzato senza l'avviso della descrizione comando. Quando l'utente ha eseguito l'accesso senza MFA, il menu Admin (Not Enabled) viene visualizzato insieme alla descrizione comando che informa l'utente (spiegando l'avviso).
@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>
}
}
Se l'utente accede senza MFA, viene visualizzato l'avviso:
L'utente viene reindirizzato alla visualizzazione di abilitazione dell'autenticazione a più fattori quando si fa clic sul collegamento Amministratore :
Inviare il requisito di accesso MFA al server OpenID Connect
Il acr_values
parametro può essere usato per passare il mfa
valore richiesto dal client al server in una richiesta di autenticazione.
Nota
Il acr_values
parametro deve essere gestito nel server OpenID Connect per il funzionamento.
Client OpenID Connect ASP.NET Core
L'app client OpenID Connect di ASP.NET Core Razor Pages usa il AddOpenIdConnect
metodo per accedere al server OpenID Connect. Il acr_values
parametro viene impostato con il mfa
valore e inviato con la richiesta di autenticazione. L'oggetto OpenIdConnectEvents
viene utilizzato per aggiungerlo.
Per i valori dei parametri consigliati acr_values
, vedere Valori di riferimento del metodo di autenticazione.
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);
}
};
});
Esempio di server OpenID Connect Duende IdentityServer con ASP.NET Core Identity
Nel server OpenID Connect, implementato tramite ASP.NET Core Identity con Razor Pages, viene creata una nuova pagina denominata ErrorEnable2FA.cshtml
. Visualizzazione :
- Visualizza se proviene Identity da un'app che richiede l'autenticazione a più fattori, ma l'utente non ha attivato questo valore in Identity.
- Informa l'utente e aggiunge un collegamento per attivarlo.
@{
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>
Login
Nel metodo viene usata l'implementazione dell'interfaccia IIdentityServerInteractionService
_interaction
per accedere ai parametri della richiesta OpenID Connect. È acr_values
possibile accedere al parametro usando la AcrValues
proprietà . Quando il client lo ha inviato con mfa
set, è quindi possibile controllarne il contenuto.
Se è necessaria l'autenticazione a più fattori e l'utente in ASP.NET Core Identity ha abilitato MFA, l'account di accesso continua. Quando l'utente non dispone di MFA abilitata, l'utente viene reindirizzato alla visualizzazione ErrorEnable2FA.cshtml
personalizzata . Quindi ASP.NET Core Identity accede all'utente.
Fido2Store viene usato per verificare se l'utente ha attivato MFA usando un provider di token FIDO2 personalizzato.
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();
}
Se l'utente è già connesso, l'app client:
- Convalida comunque l'attestazione
amr
. - Può configurare l'autenticazione a più fattori con un collegamento alla visualizzazione ASP.NET Core Identity .
Forzare ASP.NET client OpenID Connect core per richiedere l'autenticazione a più fattori
Questo esempio mostra come un'app ASP.NET Core Razor Page, che usa OpenID Connect per accedere, può richiedere che gli utenti abbiano eseguito l'autenticazione tramite MFA.
Per convalidare il requisito MFA, viene creato un IAuthorizationRequirement
requisito. Questa operazione verrà aggiunta alle pagine usando un criterio che richiede l'autenticazione a più fattori.
using Microsoft.AspNetCore.Authorization;
namespace AspNetCoreRequireMfaOidc;
public class RequireMfa : IAuthorizationRequirement{}
Viene AuthorizationHandler
implementato che userà l'attestazione amr
e verificherà il valore mfa
. L'oggetto amr
id_token
viene restituito in di un'autenticazione riuscita e può avere molti valori diversi, come definito nella specifica Valori di riferimento del metodo di autenticazione.
Il valore restituito dipende dalla modalità identity di autenticazione e dall'implementazione del server OpenID Connect.
AuthorizationHandler
usa il RequireMfa
requisito e convalida l'attestazioneamr
. Il server OpenID Connect può essere implementato usando Duende Identity Server con ASP.NET Core Identity. Quando un utente accede con TOTP, l'attestazione amr
viene restituita con un valore MFA. Se si usa un'implementazione del server OpenID Connect diversa o un tipo MFA diverso, l'attestazione amr
o può avere un valore diverso. Il codice deve essere esteso anche per accettarlo.
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;
}
}
Nel file di programma il AddOpenIdConnect
metodo viene usato come schema di verifica predefinito. Il gestore di autorizzazione, usato per controllare l'attestazione amr
, viene aggiunto al contenitore Inversion of Control. Viene quindi creato un criterio che aggiunge il RequireMfa
requisito.
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();
Questo criterio viene quindi usato nella Razor pagina in base alle esigenze. I criteri possono essere aggiunti a livello globale anche per l'intera app.
[Authorize(Policy= "RequireMfa")]
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
Se l'utente esegue l'autenticazione senza MFA, l'attestazione amr
avrà probabilmente un pwd
valore. La richiesta non sarà autorizzata ad accedere alla pagina. Usando i valori predefiniti, l'utente verrà reindirizzato alla pagina Account/AccessDenied . Questo comportamento può essere modificato oppure è possibile implementare la propria logica personalizzata qui. In questo esempio viene aggiunto un collegamento in modo che l'utente valido possa configurare MFA per il proprio account.
@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>
Ora solo gli utenti che eseguono l'autenticazione con MFA possono accedere alla pagina o al sito Web. Se vengono usati diversi tipi di autenticazione a più fattori o se 2FA è corretto, l'attestazione amr
avrà valori diversi e deve essere elaborata correttamente. I diversi server OpenID Connect restituiscono anche valori diversi per questa attestazione e potrebbero non seguire la specifica Valori di riferimento del metodo di autenticazione.
Quando si esegue l'accesso senza autenticazione a più fattori(ad esempio, usando solo una password):
Ha
amr
ilpwd
valore :Accesso negato:
In alternativa, accedere usando OTP con Identity:
Risorse aggiuntive
L'autenticazione a più fattori (MFA) è un processo in cui un utente viene richiesto durante un evento di accesso per ulteriori forme di identificazione. Questo prompt potrebbe essere quello di immettere un codice da un cellulare, usare un tasto FIDO2 o per fornire un'analisi delle impronte digitali. Quando è necessaria una seconda forma di autenticazione, la sicurezza viene migliorata. Il fattore aggiuntivo non è facilmente ottenuto o duplicato da un cyberattacker.
Questo articolo illustra le aree seguenti:
- Che cos'è MFA e quali flussi MFA sono consigliati
- Configurare MFA per le pagine di amministrazione usando ASP.NET Core Identity
- Inviare il requisito di accesso MFA al server OpenID Connect
- Forzare ASP.NET client OpenID Connect core per richiedere l'autenticazione a più fattori
MFA, 2FA
L'autenticazione a più fattori richiede almeno due o più tipi di prova per un identity elemento simile a quello che si conosce, un elemento che si possiede o la convalida biometrica per l'autenticazione dell'utente.
L'autenticazione a due fattori (2FA) è simile a un subset di MFA, ma la differenza consiste nel fatto che l'autenticazione a più fattori può richiedere due o più fattori per dimostrare .identity
MFA TOTP (algoritmo password monouso basato sul tempo)
MFA con TOTP è un'implementazione supportata usando ASP.NET Core Identity. Può essere usato insieme a qualsiasi app di autenticazione conforme, tra cui:
- App Microsoft Authenticator
- Google Authenticator App
Per informazioni dettagliate sull'implementazione, vedere il collegamento seguente:
Abilitare la generazione di codice a matrice per le app di autenticazione TOTP in ASP.NET Core
Passkey MFA/FIDO2 o senza password
passkeys/FIDO2 è attualmente:
- Il modo più sicuro per ottenere l'autenticazione a più fattori.
- MFA che protegge dagli attacchi di phishing. (Oltre all'autenticazione del certificato e a Windows per le aziende)
Attualmente, ASP.NET Core non supporta direttamente passkeys/FIDO2. Passkeys/FIDO2 può essere usato per i flussi MFA o senza password.
Microsoft Entra ID fornisce il supporto per i flussi passkeys/FIDO2 e senza password. Per altre informazioni, vedere Opzioni di autenticazione senza password.
Altre forme di autenticazione a più fattori senza password non proteggono o meno dal phishing.
MFA SMS
L'autenticazione a più fattori con SMS aumenta notevolmente la sicurezza rispetto all'autenticazione della password (fattore singolo). Tuttavia, l'uso di SMS come secondo fattore non è più consigliato. Per questo tipo di implementazione esistono troppi vettori di attacco noti.
Configurare MFA per le pagine di amministrazione usando ASP.NET Core Identity
L'autenticazione a più fattori potrebbe essere costretta agli utenti ad accedere alle pagine sensibili all'interno di un'app ASP.NET Core Identity . Ciò può essere utile per le app in cui esistono diversi livelli di accesso per le diverse identità. Ad esempio, gli utenti potrebbero essere in grado di visualizzare i dati del profilo usando un account di accesso con password, ma un amministratore deve usare l'autenticazione a più fattori per accedere alle pagine amministrative.
Estendere l'account di accesso con un'attestazione MFA
Il codice demo viene configurato usando ASP.NET Core con Identity e Razor Pages. Il AddIdentity
metodo viene usato invece di AddDefaultIdentity
uno, quindi è possibile usare un'implementazione IUserClaimsPrincipalFactory
per aggiungere attestazioni a identity dopo un account di accesso riuscito.
Avviso
Questo articolo illustra l'uso di stringa di connessione. Con un database locale l'utente non deve essere autenticato, ma nell'ambiente di produzione stringa di connessione talvolta include una password per l'autenticazione. Una credenziale della password del proprietario della risorsa (ROPC) è un rischio per la sicurezza che deve essere evitato nei database di produzione. Le app di produzione devono usare il flusso di autenticazione più sicuro disponibile. Per altre informazioni sull'autenticazione per le app distribuite in ambienti di test o di produzione, vedere Proteggere i flussi di autenticazione.
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();
}
La AdditionalUserClaimsPrincipalFactory
classe aggiunge l'attestazione amr
alle attestazioni utente solo dopo un accesso riuscito. Il valore dell'attestazione viene letto dal database. L'attestazione viene aggiunta qui perché l'utente deve accedere alla visualizzazione protetta superiore solo se ha eseguito l'accesso identity con MFA. Se la vista del database viene letta direttamente dal database anziché usare l'attestazione, è possibile accedere alla vista senza MFA direttamente dopo l'attivazione dell'autenticazione a più fattori.
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;
}
}
}
Poiché l'installazione del Identity servizio è stata modificata nella Startup
classe , è necessario aggiornare i layout dell'oggetto Identity . Eseguire lo scaffolding delle Identity pagine nell'app. Definire il layout nel Identity/Account/Manage/_Layout.cshtml
file.
@{
Layout = "/Pages/Shared/_Layout.cshtml";
}
Assegnare anche il layout per tutte le pagine di gestione dalle Identity pagine:
@{
Layout = "_Layout.cshtml";
}
Convalidare il requisito MFA nella pagina di amministrazione
La pagina di amministrazione Razor verifica che l'utente abbia eseguito l'accesso tramite MFA. OnGet
Nel metodo viene identity usato per accedere alle attestazioni utente. L'attestazione amr
viene verificata per il valore mfa
. Se manca identity questa attestazione o è false
, la pagina reindirizza alla pagina Abilita MFA. Ciò è possibile perché l'utente ha già eseguito l'accesso, ma senza MFA.
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();
}
}
}
Logica dell'interfaccia utente per attivare o disattivare le informazioni di accesso utente
Nel file di programma è stato aggiunto un criterio di autorizzazione. Il criterio richiede l'attestazione amr
con il valore mfa
.
builder.Services.AddAuthorization(options =>
options.AddPolicy("TwoFactorEnabled",
x => x.RequireClaim("amr", "mfa")));
Questo criterio può quindi essere usato nella _Layout
visualizzazione per visualizzare o nascondere il menu Admin con l'avviso:
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
@inject IAuthorizationService AuthorizationService
Se l'oggetto ha eseguito l'accesso identity tramite MFA, il menu Admin viene visualizzato senza l'avviso della descrizione comando. Quando l'utente ha eseguito l'accesso senza MFA, il menu Admin (Not Enabled) viene visualizzato insieme alla descrizione comando che informa l'utente (spiegando l'avviso).
@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>
}
}
Se l'utente accede senza MFA, viene visualizzato l'avviso:
L'utente viene reindirizzato alla visualizzazione di abilitazione dell'autenticazione a più fattori quando si fa clic sul collegamento Amministratore :
Inviare il requisito di accesso MFA al server OpenID Connect
Il acr_values
parametro può essere usato per passare il mfa
valore richiesto dal client al server in una richiesta di autenticazione.
Nota
Il acr_values
parametro deve essere gestito nel server OpenID Connect per il funzionamento.
Client OpenID Connect ASP.NET Core
L'app client OpenID Connect di ASP.NET Core Razor Pages usa il AddOpenIdConnect
metodo per accedere al server OpenID Connect. Il acr_values
parametro viene impostato con il mfa
valore e inviato con la richiesta di autenticazione. L'oggetto OpenIdConnectEvents
viene utilizzato per aggiungerlo.
Per i valori dei parametri consigliati acr_values
, vedere Valori di riferimento del metodo di autenticazione.
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);
}
};
});
Esempio di server OpenID Connect IdentityServer 4 con ASP.NET Core Identity
Nel server OpenID Connect, implementato usando ASP.NET Core Identity con le visualizzazioni MVC, viene creata una nuova visualizzazione denominata ErrorEnable2FA.cshtml
. Visualizzazione :
- Visualizza se proviene Identity da un'app che richiede l'autenticazione a più fattori, ma l'utente non ha attivato questo valore in Identity.
- Informa l'utente e aggiunge un collegamento per attivarlo.
@{
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>
Login
Nel metodo viene usata l'implementazione dell'interfaccia IIdentityServerInteractionService
_interaction
per accedere ai parametri della richiesta OpenID Connect. È acr_values
possibile accedere al parametro usando la AcrValues
proprietà . Quando il client lo ha inviato con mfa
set, è quindi possibile controllarne il contenuto.
Se è necessaria l'autenticazione a più fattori e l'utente in ASP.NET Core Identity ha abilitato MFA, l'account di accesso continua. Quando l'utente non dispone di MFA abilitata, l'utente viene reindirizzato alla visualizzazione ErrorEnable2FA.cshtml
personalizzata . Quindi ASP.NET Core Identity accede all'utente.
//
// 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
Il ExternalLoginCallback
metodo funziona come l'account di accesso locale Identity . La AcrValues
proprietà viene controllata per il mfa
valore . Se il valore è presente, l'autenticazione mfa
a più fattori viene forzata prima del completamento dell'account di accesso, ad esempio reindirizzata alla ErrorEnable2FA
visualizzazione.
//
// 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
Se l'utente è già connesso, l'app client:
- Convalida comunque l'attestazione
amr
. - Può configurare l'autenticazione a più fattori con un collegamento alla visualizzazione ASP.NET Core Identity .
Forzare ASP.NET client OpenID Connect core per richiedere l'autenticazione a più fattori
Questo esempio mostra come un'app ASP.NET Core Razor Page, che usa OpenID Connect per accedere, può richiedere che gli utenti abbiano eseguito l'autenticazione tramite MFA.
Per convalidare il requisito MFA, viene creato un IAuthorizationRequirement
requisito. Questa operazione verrà aggiunta alle pagine usando un criterio che richiede l'autenticazione a più fattori.
using Microsoft.AspNetCore.Authorization;
namespace AspNetCoreRequireMfaOidc
{
public class RequireMfa : IAuthorizationRequirement{}
}
Viene AuthorizationHandler
implementato che userà l'attestazione amr
e verificherà il valore mfa
. L'oggetto amr
id_token
viene restituito in di un'autenticazione riuscita e può avere molti valori diversi, come definito nella specifica Valori di riferimento del metodo di autenticazione.
Il valore restituito dipende dalla modalità identity di autenticazione e dall'implementazione del server OpenID Connect.
AuthorizationHandler
usa il RequireMfa
requisito e convalida l'attestazioneamr
. Il server OpenID Connect può essere implementato usando IdentityServer4 con ASP.NET Core Identity. Quando un utente accede con TOTP, l'attestazione amr
viene restituita con un valore MFA. Se si usa un'implementazione del server OpenID Connect diversa o un tipo MFA diverso, l'attestazione amr
o può avere un valore diverso. Il codice deve essere esteso anche per accettarlo.
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;
}
}
Startup.ConfigureServices
Nel metodo il AddOpenIdConnect
metodo viene usato come schema di verifica predefinito. Il gestore di autorizzazione, usato per controllare l'attestazione amr
, viene aggiunto al contenitore Inversion of Control. Viene quindi creato un criterio che aggiunge il RequireMfa
requisito.
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();
}
Questo criterio viene quindi usato nella Razor pagina in base alle esigenze. I criteri possono essere aggiunti a livello globale anche per l'intera app.
[Authorize(Policy= "RequireMfa")]
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
Se l'utente esegue l'autenticazione senza MFA, l'attestazione amr
avrà probabilmente un pwd
valore. La richiesta non sarà autorizzata ad accedere alla pagina. Usando i valori predefiniti, l'utente verrà reindirizzato alla pagina Account/AccessDenied . Questo comportamento può essere modificato oppure è possibile implementare la propria logica personalizzata qui. In questo esempio viene aggiunto un collegamento in modo che l'utente valido possa configurare MFA per il proprio account.
@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>
Ora solo gli utenti che eseguono l'autenticazione con MFA possono accedere alla pagina o al sito Web. Se vengono usati diversi tipi di autenticazione a più fattori o se 2FA è corretto, l'attestazione amr
avrà valori diversi e deve essere elaborata correttamente. I diversi server OpenID Connect restituiscono anche valori diversi per questa attestazione e potrebbero non seguire la specifica Valori di riferimento del metodo di autenticazione.
Quando si esegue l'accesso senza autenticazione a più fattori(ad esempio, usando solo una password):
Ha
amr
ilpwd
valore :Accesso negato:
In alternativa, accedere usando OTP con Identity: