Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Nota
Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 10 di questo articolo.
Avviso
Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere i criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 10 di questo articolo.
L'autenticazione a più fattori (MFA) è un processo in cui un utente viene richiesto durante l'accesso per più forme di identificazione. Il prompt potrebbe richiedere all'utente di immettere un codice da un cellulare, usare un tasto FIDO2 o 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 offre una panoramica dell'autenticazione a più fattori in ASP.NET Core e dei flussi di autenticazione consigliati con esempi che illustrano come:
- Configurare MFA per le pagine di amministrazione usando ASP.NET Core Identity.
- Inviare un requisito di accesso MFA al server OpenID Connect.
- Fare in modo che il client OpenID Connect di ASP.NET Core richieda l'autenticazione a più fattori.
Visualizzare o scaricare il codice di esempio (come scaricare).
MFA rispetto a 2FA
L'autenticazione a più fattori richiede almeno due fattori di verifica per verificare l'identità. I tipi di prova possono essere qualcosa di noto, qualcosa che si possiede o la convalida biometrica per l'autenticazione dell'utente.
L'autenticazione a due fattori (2FA) è simile a un subset di MFA. 2FA richiede esattamente due tipi di prova, mentre l'autenticazione a più fattori può richiedere due o più fattori per dimostrare l'identità.
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.
Autenticazione MFA TOTP (algoritmo di password monouso basato sul tempo)
L'autenticazione a più fattori con 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 QR per le app di autenticazione TOTP in ASP.NET Core.
Per disabilitare il supporto per MFA TOTP, configurare l'autenticazione usando il AddIdentity metodo anziché il AddDefaultIdentity metodo . Il AddDefaultIdentity metodo chiama internamente il AddDefaultTokenProviders metodo , che registra più provider di token, tra cui uno per MFA TOTP. Per registrare solo provider di token specifici, chiamare il AddTokenProvider metodo per ogni provider richiesto. Per ulteriori informazioni sui provider di token disponibili, vedere il codice sorgente di riferimento 'AddDefaultTokenProviders' nel repository GitHub dotnet/aspnetcore.
Nota
I collegamenti della documentazione al codice sorgente di riferimento .NET in genere caricano il ramo predefinito del repository, che rappresenta lo sviluppo corrente per la prossima versione di .NET. Per selezionare un tag per una versione specifica, utilizzare il menu a discesa Cambia rami o tag. Per ulteriori informazioni, vedere Come selezionare un tag di versione del codice sorgente di ASP.NET Core (dotnet/AspNetCore.Docs #26205).
Passkey MFA/FIDO2 o senza password
L'approccio passkeys/FIDO2 è attualmente:
- Il modo più sicuro per implementare l'autenticazione a più fattori.
- MFA che protegge dagli attacchi di phishing (anche autenticazione del certificato e Windows per le aziende).
ASP.NET Core supporta passkey usando ASP.NET Core Identity. Passkeys/FIDO2 può essere usato per i flussi MFA o senza password. Per altre informazioni, vedere Abilitare le passkey api di autenticazione Web (WebAuthn).
Microsoft Entra ID fornisce supporto per le passkey/FIDO2 e i meccanismi senza password. Per altre informazioni, vedere Metodi di autenticazione in Microsoft Entra ID - passkeys (FIDO2).
Altre forme di autenticazione a più fattori senza password non proteggono o non possono proteggersi dal phishing.
Autenticazione a più fattori (MFA) tramite 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.
Per altre informazioni, vedere Linee guida per la digitalizzazione Identity NIST (pubblicazione speciale 800-63B).
Configurare MFA per le pagine di amministrazione con ASP.NET Core Identity
È possibile forzare l'autenticazione a più fattori per gli utenti per abilitare l'accesso alle pagine sensibili all'interno di un'app ASP.NET Core Identity. Questo approccio può essere utile per le app in cui esistono diversi livelli di accesso per identità diverse. Ad esempio, gli utenti potrebbero essere in grado di visualizzare i dati del profilo usando un processo di accesso con password, ma un amministratore deve usare l'autenticazione a più fattori per accedere alle pagine amministrative.
Estendi la procedura di accesso con una dichiarazione MFA
La configurazione del codice di esempio usa ASP.NET Core con Identity e Razor Pages. Il AddIdentity metodo viene usato invece di AddDefaultIdentity, in modo che un'implementazione IUserClaimsPrincipalFactory possa essere usata per aggiungere attestazioni all'identità dopo l'accesso.
Avviso
Questo articolo illustra l'uso di stringa di connessione. Quando un database locale viene usato per lo sviluppo e il test, l'autenticazione utente del database tramite il stringa di connessione non è necessaria. Negli ambienti di produzione, le stringhe di connessione includono talvolta una password per autenticare l'accesso al database o le operazioni del database. Una credenziale password del proprietario della risorsa (ROPC) in una stringa di connessione è un rischio per la sicurezza che deve essere evitata nelle applicazioni 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 ASP.NET Argomenti sulla sicurezza di base.
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 (attestazione Authentication Methods References) alle attestazioni utente solo dopo un accesso riuscito. Il valore del claim viene letto dal database. Il claim viene aggiunto qui perché l'utente deve accedere alla vista con livello di protezione più elevato solo se l'identità ha effettuato l'accesso 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é la configurazione del servizio Identity è stata modificata nella classe Startup, è necessario aggiornare i layout di Identity:
Generare le Identity pagine nell'app.
Definire il layout nel Identityfile /Account/Manage/_Layout.cshtml .
@{ Layout = "/Pages/Shared/_Layout.cshtml"; }Assegna inoltre il layout per tutte le pagine di gestione dalle pagine Identity:
@{ Layout = "_Layout.cshtml"; }
Convalidare il requisito MFA nella pagina di amministrazione
La pagina di amministrazione Razor verifica che l'utente sia connesso tramite MFA. Nel metodo OnGet l'identità viene usata per accedere alle attestazioni utente. L'attestazione amr viene verificata per il valore mfa. Se all'identità manca questa dichiarazione o è false, la pagina viene reindirizzata alla pagina Abilita autenticazione a più fattori. Questa azione è 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/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'utente ha effettuato l'accesso tramite MFA, il menu Admin viene visualizzato senza il tooltip di avviso.
Quando l'utente ha effettuato l'accesso senza MFA, viene visualizzato il menu Admin (Not Enabled) insieme al suggerimento che informa l'utente e spiega 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, l'opzione Admin (Non abilitato) visualizza l'avviso :If the user sign in without MFA, the Admin option shows the (Not Enabled) warning:
Quando l'utente seleziona l'opzione Amministratore , viene reindirizzato a una visualizzazione in cui può abilitare l'autenticazione a più fattori:
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 di questo approccio.
Client OpenID Connect ASP.NET Core
L'app client ASP.NET Core Razor Pages OpenID Connect usa il metodo AddOpenIdConnect per accedere al server OpenID Connect. Il acr_values parametro viene impostato con il mfa valore e inviato con la richiesta di autenticazione. Viene OpenIdConnectEvents utilizzato per aggiungere questo valore.
Per i valori consigliati del parametro acr_values, consultare la specifica IETF Authentication Method Reference Values.
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: Server OpenID Connect Duende IdentityServer
L'esempio seguente illustra il 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 pagina:
- Visualizza se proviene Identity da un'app che richiede l'autenticazione a più fattori, ma l'utente non ha attivato l'autenticazione a più fattori 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. Si accede al parametro acr_values mediante la proprietà AcrValues. Poiché 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 è abilitato con MFA, il processo di accesso continua. Quando l'utente non dispone di MFA abilitata, l'utente viene reindirizzato alla visualizzazione ErrorEnable2FA.cshtmlpersonalizzata . Poi ASP.NET Core Identity autentica l'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 ha già eseguito l'accesso, l'applicazione client:
Convalida comunque l'attestazione
amr.È possibile configurare l'autenticazione a più fattori con un collegamento alla visualizzazione ASP.NET Core Identity, ad esempio Enable MFA:
Forzare il client ASP.NET Core OpenID Connect a richiedere l'autenticazione a più fattori
Questo esempio mostra come un'applicazione Page ASP.NET Core Razor, che utilizza OpenID Connect per eseguire l'accesso, possa richiedere che gli utenti siano autenticati tramite MFA.
Per convalidare il requisito MFA, viene creato un IAuthorizationRequirement requisito. Il requisito viene aggiunto alle pagine tramite un criterio che richiede l'autenticazione a più fattori.
using Microsoft.AspNetCore.Authorization;
namespace AspNetCoreRequireMfaOidc;
public class RequireMfa : IAuthorizationRequirement{}
Si implementa un AuthorizationHandler per usare il claim amr e verificare che il valore sia mfa. Il amr viene restituito nel id_token di un'autenticazione riuscita e può avere molti valori diversi, come definito nella specifica IETF Authentication Method Reference Values.
Il valore restituito dipende dalla modalità di autenticazione dell'identità 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 tramite 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 può avere un valore diverso. Il codice deve essere esteso per accettare gli altri valori possibili.
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();
Il criterio viene quindi usato nella pagina Razor come richiesto. Il criterio può anche essere aggiunto a livello globale per l'intera app.
[Authorize(Policy= "RequireMfa")]
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
Se l'utente si autentica senza MFA, il claim amr ha probabilmente valore pwd (password). Di conseguenza, la richiesta non è autorizzata ad accedere a questa pagina. Usando i valori predefiniti, l'utente viene reindirizzato alla pagina Account>AccessDenied . Questo comportamento può essere modificato oppure è possibile implementare una logica personalizzata. 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>
Dopo questa modifica, solo gli utenti che eseguono l'autenticazione con MFA possono accedere alla pagina o al sito Web. Se vengono usati tipi di autenticazione a più fattori o se è consentito l'autenticazione a più fattori, l'attestazione amr ha valori diversi e deve essere elaborata correttamente. Diversi server OpenID Connect restituiscono anche valori diversi per questa attestazione. Questi valori potrebbero non seguire la specifica IETF Authentication Method Reference Values (Valori di riferimento del metodo di autenticazione IETF ).
Quando l'utente accede senza MFA (ad esempio, usando solo una password):
Il claim
amrha come valore la passwordpwd:
Accesso negato:
In alternativa, quando l'utente accede tramite OTP con Identity, il claim amr ha valore mfa:
Personalizzazione dei parametri OIDC e OAuth
L'opzione AdditionalAuthorizationParameters dei gestori di autenticazione OAuth e OIDC consente di personalizzare i parametri del messaggio di autorizzazione solitamente inclusi nella stringa di query di reindirizzamento:
builder.Services.AddAuthentication().AddOpenIdConnect(options =>
{
options.AdditionalAuthorizationParameters.Add("prompt", "login");
options.AdditionalAuthorizationParameters.Add("audience", "https://api.example.com");
});
Contenuti correlati
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 il client ASP.NET Core OpenID Connect a richiedere l'autenticazione a più fattori
MFA (Autenticazione a più fattori), 2FA (Autenticazione a due fattori)
L'autenticazione a più fattori richiede almeno due o più tipi di prova per un'identità come qualcosa di noto, qualcosa di cui si dispone o una 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 l'identità.
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.
Autenticazione MFA TOTP (algoritmo di 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 QR 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 i metodi di estensione in IdentityBuilderExtensions.
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 supporto per le passkey/FIDO2 e i meccanismi 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.
Autenticazione a più fattori (MFA) tramite 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 richiesta agli utenti per accedere alle pagine sensibili 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 metodo AddIdentity viene usato invece di AddDefaultIdentity uno, quindi è possibile usare un'implementazione IUserClaimsPrincipalFactory per aggiungere attestazioni all'identità dopo un accesso riuscito.
Avviso
Questo articolo illustra l'uso di stringa di connessione. Quando un database locale viene usato per lo sviluppo e il test, l'autenticazione utente del database tramite il stringa di connessione non è necessaria. Negli ambienti di produzione, le stringhe di connessione includono talvolta una password per autenticare l'accesso al database o le operazioni del database. Una credenziale password del proprietario della risorsa (ROPC) in una stringa di connessione è un rischio per la sicurezza che deve essere evitata nelle applicazioni 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 ASP.NET Argomenti sulla sicurezza di base.
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. La richiesta di autenticazione viene aggiunta qui perché l'utente può accedere alla vista protetta avanzata solo se l'identità ha effettuato l'accesso con autenticazione multi-fattore (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 servizio Identity è stata modificata nella classe Startup, è necessario aggiornare i layout di Identity. Generare le Identity pagine nell'app. Definire il layout nel Identity/Account/Manage/_Layout.cshtml file.
@{
Layout = "/Pages/Shared/_Layout.cshtml";
}
Inoltre, assegnare il layout a tutte le pagine di gestione dalle pagine Identity.
@{
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. Nel metodo OnGet l'identità viene usata per accedere alle attestazioni utente. L'attestazione amr viene verificata per il valore mfa. Se all'identità manca questa dichiarazione o è false, la pagina viene reindirizzata alla pagina Abilita autenticazione a più fattori. 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. La politica richiede la dichiarazione 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'identità ha eseguito l'accesso tramite MFA, il menu amministratore viene visualizzato senza l'avviso tooltip. Quando l'utente ha eseguito l'accesso senza MFA, il menu Admin (Not Enabled) viene visualizzato insieme alla descrizione comando che informa l'utente (fornendo la spiegazione dell'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 pagina di abilitazione dell'autenticazione a due fattori quando si fa clic sul link 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 aggiungere questo.
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 Identity proviene da un'app che richiede l'autenticazione multi-fattore, ma l'utente non l'ha attivata 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. Il parametro acr_values viene accesso usando la proprietà AcrValues. 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, allora il login può procedere. Quando l'utente non dispone di MFA abilitata, l'utente viene reindirizzato alla visualizzazione ErrorEnable2FA.cshtmlpersonalizzata . Poi ASP.NET Core Identity autentica l'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à collegato, l'app cliente:
- Convalida comunque l'attestazione
amr. - È possibile configurare l'autenticazione a più fattori con un collegamento alla vista ASP.NET Core Identity.
Forzare il client ASP.NET Core OpenID Connect a 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 implementato un AuthorizationHandler che userà l'attestazione amr e controllerà il valore mfa. Il amr viene restituito nel id_token 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à di autenticazione dell'identità 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 utilizza un'implementazione del server OpenID Connect diversa o un tipo di MFA diverso, l'attestazione amr potrà, o potrà, 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 va bene, la dichiarazione 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):
Il
amrha il valorepwd:
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 il client ASP.NET Core OpenID Connect a richiedere l'autenticazione a più fattori
MFA (Autenticazione a più fattori), 2FA (Autenticazione a due fattori)
L'autenticazione a più fattori richiede almeno due o più tipi di prova per un'identità come qualcosa di noto, qualcosa di cui si dispone o una 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 l'identità.
Autenticazione MFA TOTP (algoritmo di 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 QR per le app autenticatori 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 supporto per le passkey/FIDO2 e i meccanismi 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.
Autenticazione a più fattori (MFA) tramite 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 richiesta agli utenti per accedere alle pagine sensibili 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 metodo AddIdentity viene usato invece di AddDefaultIdentity uno, quindi è possibile usare un'implementazione IUserClaimsPrincipalFactory per aggiungere attestazioni all'identità dopo un accesso riuscito.
Avviso
Questo articolo illustra l'uso di stringa di connessione. Quando un database locale viene usato per lo sviluppo e il test, l'autenticazione utente del database tramite il stringa di connessione non è necessaria. Negli ambienti di produzione, le stringhe di connessione includono talvolta una password per autenticare l'accesso al database o le operazioni del database. Una credenziale password del proprietario della risorsa (ROPC) in una stringa di connessione è un rischio per la sicurezza che deve essere evitata nelle applicazioni 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 ASP.NET Argomenti sulla sicurezza di base.
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. La richiesta di autenticazione viene aggiunta qui perché l'utente può accedere alla vista protetta avanzata solo se l'identità ha effettuato l'accesso con autenticazione multi-fattore (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 servizio Identity è stata modificata nella classe Startup, è necessario aggiornare i layout di Identity. Generare le Identity pagine nell'app. Definire il layout nel Identity/Account/Manage/_Layout.cshtml file.
@{
Layout = "/Pages/Shared/_Layout.cshtml";
}
Inoltre, assegnare il layout a tutte le pagine di gestione dalle pagine Identity.
@{
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. Nel metodo OnGet l'identità viene usata per accedere alle attestazioni utente. L'attestazione amr viene verificata per il valore mfa. Se all'identità manca questa dichiarazione o è false, la pagina viene reindirizzata alla pagina Abilita autenticazione a più fattori. 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. La politica richiede la dichiarazione 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'identità ha eseguito l'accesso tramite MFA, il menu amministratore viene visualizzato senza l'avviso tooltip. Quando l'utente ha eseguito l'accesso senza MFA, il menu Admin (Not Enabled) viene visualizzato insieme alla descrizione comando che informa l'utente (fornendo la spiegazione dell'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 pagina di abilitazione dell'autenticazione a due fattori quando si fa clic sul link 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 aggiungere questo.
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 Identity proviene da un'app che richiede l'autenticazione multi-fattore, ma l'utente non l'ha attivata 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. Il parametro acr_values viene accesso usando la proprietà AcrValues. 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, allora il login può procedere. Quando l'utente non dispone di MFA abilitata, l'utente viene reindirizzato alla visualizzazione ErrorEnable2FA.cshtmlpersonalizzata . Poi ASP.NET Core Identity autentica l'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 metodo ExternalLoginCallback funziona come il login locale Identity. La AcrValues proprietà viene controllata per il mfa valore . Se il valore mfa è presente, l'autenticazione a più fattori viene forzata prima che il login sia completato, ad esempio reindirizzata alla schermata ErrorEnable2FA.
//
// 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à collegato, l'app cliente:
- Convalida comunque l'attestazione
amr. - È possibile configurare l'autenticazione a più fattori con un collegamento alla vista ASP.NET Core Identity.
Forzare il client ASP.NET Core OpenID Connect a 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 implementato un AuthorizationHandler che userà l'attestazione amr e controllerà il valore mfa. Il amr viene restituito nel id_token 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à di autenticazione dell'identità 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 utilizza un'implementazione del server OpenID Connect diversa o un tipo di MFA diverso, l'attestazione amr potrà, o potrà, 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 metodo Startup.ConfigureServices, il metodo AddOpenIdConnect 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 va bene, la dichiarazione 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):
Il
amrha il valorepwd:
Accesso negato:
In alternativa, accedere usando OTP con Identity: