Leggere in inglese

Condividi tramite


Configurare l'autenticazione del bearer JWT in ASP.NET Core

Di Damien Bowden

L'autenticazione JWT (JSON Web Token) viene comunemente utilizzata per le API. Anche se funziona in modo analogo all'autenticazione di cookie, il provider di identità rilascia un token JWT o altri token in caso di autenticazione riuscita. Questi token possono quindi essere inviati ad altri server per l'autenticazione, a differenza dei cookie che vengono inviati solo al dominio emittente. Un token JWT è un token autonomo che incapsula le informazioni per una risorsa API o un client. Il client che ha richiesto il token JWT può richiedere dati da una risorsa API utilizzando l'intestazione Authorization e un token Bearer.

Autenticazione JWT Bearer fornisce:

  • Authentication: quando si utilizza JwtBearerHandler, i token di accesso sono essenziali per l'autenticazione. Il JwtBearerHandler convalida il token ed estrae l'identità dell'utente dalle dichiarazioni.
  • Autorizzazione: i token di autorizzazione consentono l'autorizzazione fornendo una raccolta di dichiarazioni che rappresentano i permessi dell'utente o dell'applicazione, similmente a un cookie.
  • Autorizzazione delegata: quando viene utilizzato un token di accesso specifico dell'utente per l'autenticazione tra le API anziché un token di accesso generale all'applicazione, il processo è noto come autorizzazione delegata.

Per un'introduzione all'autenticazione JWT Bearer, vedere JSON Web Tokens.Visualizzare o scaricare il codice di esempio

Questo articolo illustra le aree seguenti:

  • Tipi di token
  • Uso di token JWT per proteggere un'API
  • In che modo OIDC/OAuth rientra in questo contesto?
  • Implementazione dell'autenticazione del token di connessione JWT
  • Approcci consigliati per creare un JSON Web Token (JWT)

Tipi di token

Esistono numerosi tipi di token e formati. La generazione di token di accesso o token ID personalizzati è sconsigliata, ad eccezione dei test. Token creati automaticamente che non rispettano gli standard stabiliti:

  • Può causare vulnerabilità di sicurezza.
  • Sono adatti solo per i sistemi chiusi.

È consigliabile usare OpenID Connect 1.0 o uno standard OAuth per la creazione di token di accesso destinati all'accesso alle API.

Token di accesso

Token di accesso:

  • Stringhe usate da un'app client per effettuare richieste al server che implementa un'API.
  • Può variare in formato. Api diverse possono usare formati diversi per i token.
  • Può essere crittografato.
  • Non deve mai essere letto o interpretato da un client Web o un'app dell'interfaccia utente che contiene il token di accesso.
  • Sono destinati esclusivamente all'esecuzione di richieste a un'API.
  • Di solito, viene inviato all'API nell'intestazione di richiesta autorizzazione come token bearer.

Vedi Il framework di autorizzazione OAuth 2.0

Token di accesso alle applicazioni e token di accesso delegati

I token di accesso possono essere token di accesso dell'applicazione o token di accesso delegati. I token hanno attestazioni diverse e vengono gestiti e archiviati in modo diverso. Un token di accesso applicazione viene in genere archiviato una volta nell'app fino alla sua scadenza, mentre un token di accesso delegato viene archiviato per utente, in un cookie o in una cache sicura del server.

È consigliabile usare i token di accesso utente delegati ogni volta che un utente è coinvolto. Le API downstream possono richiedere un token di accesso utente delegato per conto dell'utente autenticato.

Token di accesso vincolati dal mittente

I token di accesso possono essere usati come token di connessione o token vincolati dal mittente per accedere alle risorse. I token vincolati dal mittente richiedono al client richiedente di dimostrare il possesso di una chiave privata per usare il token. La dimostrazione del possesso di una chiave privata garantisce che il token non possa essere usato in modo indipendente. I token vincolati dal mittente possono essere implementati in due modi:

ID del token

I token ID sono token di sicurezza che confermano l'autenticazione corretta di un utente. I token consentono al client di verificare l'identità dell'utente. Il server token JWT rilascia token ID contenenti attestazioni con informazioni utente. I token ID sono sempre in formato JWT.

I token ID non devono mai essere usati per accedere alle API.

Altri token

Esistono molti tipi di token, inclusi i token di accesso e ID, come specificato dagli standard OpenID Connect e OAuth. I token di aggiornamento possono essere usati per aggiornare un'app dell'interfaccia utente senza ripetere l'autenticazione dell'utente. token OAuth JAR inviano in modo sicuro le richieste di autorizzazione. I flussi di credenziali verificabili usano tipi JWT per l'emissione o la verifica delle credenziali. È fondamentale usare i token in base alle specifiche. Per altre informazioni, vedere i collegamenti agli standard forniti più avanti in questo articolo.

Uso di token JWT per proteggere un'API

Quando si usano token di accesso JWT per l'autorizzazione API, l'API concede o nega l'accesso in base al token fornito. Se la richiesta non è autorizzata, viene restituita una risposta 401 o 403. L'API non deve reindirizzare l'utente al provider di identità per ottenere un nuovo token o richiedere autorizzazioni aggiuntive. L'app che usa l'API è responsabile dell'acquisizione di un token appropriato. In questo modo si garantisce una netta separazione delle problematiche tra l'API (autorizzazione) e l'app client che la utilizza (autenticazione).

Nota

HTTP consente anche di restituire 404 per risorsa non autorizzata, in modo da non rivelare informazioni sull'esistenza di risorse a client non autorizzati.

401 Non autorizzato

Una risposta 401 Non autorizzata indica che il token di accesso fornito non soddisfa gli standard richiesti. Ciò potrebbe essere dovuto a diversi motivi, tra cui:

  • firma non valida: la firma del token non corrisponde, suggerendo potenziali manomissioni.
  • Scadenza: il token è scaduto e non è più valido.
  • Attestazioni non corrette: le attestazioni critiche all'interno del token, ad esempio i destinatari (aud) o l'autorità emittente (iss), sono mancanti o non valide.

Nota

Dalla semantica HTTP RFC 9110: il server che genera una risposta 401 DEVE inviare un campo di intestazione WWW-Authenticate (sezione 11.6.1) contenente almeno una richiesta applicabile alla risorsa di destinazione.

Le specifiche OAuth forniscono linee guida dettagliate sulle attestazioni necessarie e sulla relativa convalida.

403 Vietato

Una risposta 403 Accesso negato indica in genere che l'utente autenticato non dispone delle autorizzazioni necessarie per accedere alla risorsa richiesta. Ciò è diverso dai problemi di autenticazione, ad esempio un token non valido e non è correlato alle attestazioni standard all'interno del token di accesso.

In ASP.NET Core è possibile applicare l'autorizzazione usando:

Requisiti e criteri: definire requisiti personalizzati, ad esempio "Deve essere un amministratore" e associarli ai criteri. Autorizzazione basata sui ruoli: assegnare utenti ai ruoli, ad esempio "Amministratore", "Editor" e limitare l'accesso in base a tali ruoli.

Quale ruolo hanno OIDC e/o OAuth quando si usano token di accesso?

Quando un'API usa token di accesso JWT per l'autorizzazione, l'API convalida solo il token di accesso, non sul modo in cui è stato ottenuto il token.

OpenID Connect (OIDC) e OAuth 2.0 forniscono framework standardizzati e sicuri per l'acquisizione di token. L'acquisizione del token varia a seconda del tipo di app. A causa della complessità dell'acquisizione di token sicuri, è consigliabile basarsi su questi standard:

  • Per le app che agiscono per conto di un utente e di un'applicazione: OIDC è la scelta preferita, abilitando l'accesso utente delegato. Nelle app Web il flusso di codice riservato con chiave di verifica per lo scambio di codice (PKCE) è consigliato per una maggiore sicurezza.
    • Se l'app chiamante è un'app ASP.NET Core con autenticazione OIDC lato server, è possibile usare l'opzione SaveTokens per archiviare il token di accesso in un per usarlo successivamente tramite .
  • Se l'app non ha un utente: il flusso di credenziali client OAuth 2.0 è adatto per ottenere i token di accesso dell'applicazione.

Implementazione dell'autenticazione del token di connessione JWT

È possibile usare pacchetto NuGet Microsoft.AspNetCore.Authentication.JwtBearer per convalidare i token di connessione JWT.

I token JWT devono essere convalidati completamente in un'API. È necessario convalidare quanto segue:

  • Firma, per attendibilità e integrità. In questo modo si garantisce che il token sia stato creato dal servizio token sicuro designato e non sia stato manomesso.
  • Dichiarazione dell'emittente con il valore atteso.
  • Dichiarazione del pubblico con il valore previsto.
  • Scadenza del token.

Per i token di accesso OAuth 2.0 sono necessarie le attestazioni seguenti: iss, exp, aud, sub, client_id, iate jti.

Se una di queste attestazioni o valori non è corretta, l'API deve restituire una risposta 401.

Validazione di base del token di autorizzazione JWT

Un'implementazione di base del AddJwtBearer può verificare solo il destinatario e chi emette. La firma deve essere convalidata in modo che il token possa essere considerato attendibile e che non sia stato manomesso.

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(jwtOptions =>
{
	jwtOptions.Authority = "https://{--your-authority--}";
	jwtOptions.Audience = "https://{--your-audience--}";
});

Convalida esplicita del token al portatore JWT

Il metodo AddJwtBearer fornisce più configurazioni. Alcuni provider di token sicuri usano un indirizzo di metadati non standard e il parametro può essere configurato in modo esplicito. L'API può accettare più emittenti o gruppi di destinatari.

Non è necessario definire in modo esplicito i parametri. Le definizioni dipendono dai valori delle affermazioni del token di accesso e dal server di token sicuro utilizzato per convalidare il token di accesso. Se possibile, è consigliabile usare i valori predefiniti.

Vedi Assegnazione delle attestazioni dettagli di MapInboundClaims.

builder.Services.AddAuthentication()
.AddJwtBearer("some-scheme", jwtOptions =>
{
	jwtOptions.MetadataAddress = builder.Configuration["Api:MetadataAddress"];
	// Optional if the MetadataAddress is specified
	jwtOptions.Authority = builder.Configuration["Api:Authority"];
	jwtOptions.Audience = builder.Configuration["Api:Audience"];
	jwtOptions.TokenValidationParameters = new TokenValidationParameters
	{
		ValidateIssuer = true,
		ValidateAudience = true,
		ValidateIssuerSigningKey = true,
		ValidAudiences = builder.Configuration.GetSection("Api:ValidAudiences").Get<string[]>(),
		ValidIssuers = builder.Configuration.GetSection("Api:ValidIssuers").Get<string[]>()
	};

	jwtOptions.MapInboundClaims = false;
});

JWT con più schemi

Le API spesso devono contenere token di accesso da diverse autorità emittenti. È possibile supportare più emittenti di token in un'API:

  • API separate: creare API distinte con schemi di autenticazione dedicati per ogni autorità emittente.
  • AddPolicyScheme Questo metodo può definire più schemi di autenticazione e implementare la logica per selezionare lo schema appropriato in base alle proprietà del token (ad esempio emittente, attestazioni). Questo approccio consente una maggiore flessibilità all'interno di una singola API.

Forzare l'autenticazione del bearer

SetDefaultPolicy può essere usato per richiedere l'autenticazione per tutte le richieste anche agli endpoint senza un attributo [Authorize]. SetDefaultPolicy configura i criteri usati per gli endpoint con l'attributo [Authorize] e per impostazione predefinita richiede già utenti autenticati. Per ulteriori dettagli, consultare la documentazione per gli utenti autenticati .

var requireAuthPolicy = new AuthorizationPolicyBuilder()
	.RequireAuthenticatedUser()
	.Build();

builder.Services.AddAuthorizationBuilder()
	.SetDefaultPolicy(requireAuthPolicy);

L'attributo Authorize può essere usato anche per forzare l'autenticazione. Se vengono usati più schemi, lo schema bearer deve in genere essere impostato come schema di autenticazione predefinito o specificato tramite [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme]).

Autorizzazione nei controller:

[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{

Autorizzazione nelle API minime:

app.MapGet("/hello", [Authorize] () => "Hi");

La gestione non sicura dei token di accesso, ad esempio l'autenticazione debole o l'archiviazione di token nell'archiviazione lato client vulnerabile, può causare vulnerabilità di sicurezza significative. Ad esempio, archiviare i token di accesso direttamente nel browser usando l'archiviazione locale, l'archiviazione delle sessioni o i web worker. La sezione seguente contiene le procedure consigliate per le app che usano e creano token di accesso.

Usare gli standard

Gli standard come OpenID Connect o OAuth devono sempre essere usati quando si creano token di accesso. I token di accesso devono non essere creati nelle app di produzione senza rispettare le precauzioni di sicurezza descritte in questo articolo. La creazione di token di accesso deve essere limitata agli scenari di test.

Usare chiavi asimmetriche

Le chiavi asimmetriche devono sempre essere usate quando si creano token di accesso. La chiave pubblica è disponibile negli endpoint noti e i client API possono convalidare la firma del token di accesso usando la chiave pubblica.

Non creare mai un token di accesso da una richiesta di nome utente/password

È consigliabile NON creare un token di accesso da una richiesta di nome utente/password. Le richieste di nome utente/password non sono autenticate e sono vulnerabili agli attacchi di rappresentazione e phishing. I token di accesso devono essere creati solo usando un flusso OpenID Connect o un flusso standard OAuth. La deviazione da questi standard può comportare un'app non sicura.

Usare i cookie

Per le app Web sicure, è necessario un back-end per archiviare i token di accesso in un server attendibile. Viene condiviso solo un cookie sicuro e solo tramite HTTP nel browser client. Per informazioni su come eseguire questa operazione in un'app Web ASP.NET Core, vedere la documentazione relativa all'autenticazione OIDC .

API downstream

Le API devono occasionalmente accedere ai dati utente dalle API downstream per conto dell'utente autenticato nell'app chiamante. L'implementazione di un flusso di credenziali client OAuth è un'opzione che richiede l'attendibilità completa tra le due app per le API. Un approccio più sicuro prevede l'uso di una strategia zero-trust con un token di accesso utente delegato. Questo approccio:

  • Migliora la sicurezza concedendo all'API solo le autorizzazioni necessarie per tale utente specifico.
  • Richiede all'API di creare il nuovo token di accesso per l'utente che chiama l'app e l'API.

Esistono diversi modi per implementare una strategia zero-trust con un token di accesso utente delegato:

Usare OAuth 2.0 Token Exchange per richiedere un nuovo token di accesso delegato

Questo è un buon modo per implementare questo requisito, ma è complicato se è necessario implementare il flusso OAuth.

Consulta lo scambio di token OAuth 2.0

Usare Microsoft Identity Web per conto di Flow per richiedere un nuovo token di accesso delegato

L'utilizzo della libreria di autenticazione Web Microsoft Identity rappresenta l'approccio più semplice e sicuro. Funziona soltanto con Microsoft Entra ID e Microsoft Entra External ID.

Per altre informazioni, vedere [Microsoft Identity Platform e OAuth 2.0 On-Behalf-Of flow

Usare lo stesso token di accesso delegato inviato all'API

Questo approccio non è difficile da implementare, ma il token di accesso ha accesso a tutte le API downstream. Il proxy inverso Yarp può essere usato per implementare questa operazione.

Usare il flusso di credenziali client OAuth per utilizzare un token di accesso dell'applicazione

Questa operazione è semplice da implementare, ma l'applicazione client ha accesso completo all'applicazione e non un token di accesso delegato. Il token deve essere memorizzato nella cache nell'applicazione API client.

Nota

Funziona anche qualsiasi sicurezza da app a app. L'autenticazione tramite certificati, o in Azure, un'identità gestita può essere utilizzata.

Gestione dei token di accesso

Quando si usano i token di accesso in un'applicazione client, i token di accesso devono essere ruotati, salvati in modo permanente e archiviati in un punto qualsiasi del server. In un'applicazione Web, i cookie vengono utilizzati per proteggere la sessione e possono essere utilizzati per archiviare i token tramite l'opzione SaveTokens.

SaveTokens non aggiornerà automaticamente i token di accesso, ma questa funzionalità è pianificata per .NET 10. Seguire https://github.com/dotnet/aspnetcore/issues/8175 per gli aggiornamenti. Nel frattempo, è possibile aggiornare manualmente il token di accesso come illustrato nella Blazor Web App con la documentazione OIDC o usare un pacchetto NuGet di terze parti come Duende.AccessTokenManagement.OpenIdConnect per la gestione e la gestione dei token di accesso nell'app client. Per ulteriori informazioni, vedere Gestione dei token Duende.

Nota

Se si esegue la distribuzione nell'ambiente di produzione, la cache deve funzionare correttamente in un'implementazione multiistanza. In genere è necessaria una cache persistente.

Alcuni server token sicuri crittografano i token di accesso. I token di accesso non richiedono alcun formato. Quando si usa l'introspezione OAuth, viene usato un token di riferimento anziché un token di accesso. Un'applicazione client (UI) non deve mai aprire un token di accesso perché il token di accesso non è destinato a questo. Solo un'API per cui è stato creato il token di accesso deve aprire il token di accesso.

  • Non aprire i token di accesso in un'applicazione dell'interfaccia utente
  • Non inviare il token ID alle API
  • I token di accesso possono avere qualsiasi formato
  • I token di accesso possono essere crittografati
  • I token di accesso scadono e devono essere ruotati
  • I token di accesso vengono salvati in modo permanente in un server back-end sicuro

YARP (ancora un altro proxy inverso)

YARP (Yet Another Reverse Proxy) è uno strumento efficace per gestire le richieste HTTP e inoltrare le richieste ad altre API. YARP può implementare la logica di sicurezza per l'acquisizione di nuove credenziali di accesso. YARP viene spesso usato nel back-end per l'architettura di sicurezza front-end (BFF). Il Blazor Web App con la documentazione di OIDC illustra l'uso di YARP per implementare il modello BFF.

Test delle API

I test di integrazione e i contenitori con token di accesso possono essere usati per testare le API sicure. I token di accesso possono essere creati usando lo strumento dotnet user-jwts.

Avviso

Assicurarsi che i problemi di sicurezza siano non introdotti nell'API a scopo di test. Il test diventa più complesso quando vengono usati i token di accesso delegati, poiché questi token possono essere creati solo tramite un'interfaccia utente e un flusso OpenID Connect. Se viene usato uno strumento di test per creare token di accesso delegati, le funzionalità di sicurezza devono essere disabilitate per i test. È essenziale che queste funzionalità siano disabilitate solo nell'ambiente di test.

Creare ambienti di test dedicati e isolati in cui le funzionalità di sicurezza possono essere disabilitate o modificate in modo sicuro. Assicurarsi che queste modifiche siano strettamente limitate all'ambiente di test.

Usa Swagger UI, Curl e altri strumenti API

L'interfaccia utente di Swagger e Curl sono ottimi strumenti dell'interfaccia utente per il test delle API. Affinché gli strumenti funzionino, l'API può produrre un documento OpenAPI e può essere caricato nello strumento di test client. È possibile aggiungere un flusso di sicurezza per acquisire un nuovo token di accesso al file OpenAPI dell'API.

Avviso

Non distribuire flussi di test di sicurezza non sicuri nell'ambiente di produzione.

Quando si implementa un'interfaccia utente di Swagger per un'API, in genere non è consigliabile distribuire l'interfaccia utente nell'ambiente di produzione perché la sicurezza deve essere indebolita per consentire il funzionamento.

Mappare le attestazioni da OpenID Connect

Fare riferimento al documento seguente:

Mapping, personalizzazione e trasformazione dei claim in ASP.NET Core

Standard

JSON Web Token (JWT)

il framework di autorizzazione OAuth 2.0

OAuth 2.0 dimostrazione della prova di possesso DPoP

RFC 9101 JWT-Secured Richiesta di Autorizzazione (JAR) OAuth 2.0

OAuth 2.0 autenticazione client Mutual-TLS e token di accesso Certificate-Bound

OpenID Connect 1.0

Flusso On-Behalf-Of di Microsoft Identity Platform e OAuth 2.0

Scambio di Token OAuth 2.0

profilo JWT (JSON Web Token) per i token di accesso OAuth 2.0

RFC 9110 Semantica HTTP


Risorse aggiuntive

Documentazione

Formazione

Modulo

Proteggere un'app Web .NET con il framework di gestione delle identità di ASP.NET Core - Training

Informazioni su come aggiungere l'autenticazione e l'autorizzazione a un'app Web .NET usando il framework di gestione delle identità di ASP.NET Core.

Certificazione

Microsoft Certified: Identity and Access Administrator Associate - Certifications

Illustrare le funzionalità di Microsoft Entra ID per modernizzare le soluzioni di identità, implementare soluzioni ibride e implementare la governance delle identità.