Prevenire attacchi XSRF/CSRF (Cross-Site Request Forgery) in ASP.NET Core

Di Fiyaz Hasan e Rick Anderson

La falsificazione di richiesta intersito è un attacco contro le app ospitate sul Web, tramite cui un'app Web malevola può influenzare l'interazione tra un browser client e un'app Web che si fida di tale browser. Questi attacchi sono possibili perché i Web browser inviano automaticamente alcuni tipi di token di autenticazione con ogni richiesta a un sito Web. Questa forma di exploit è nota anche come attacco con un clic o guida di sessione perché l'attacco sfrutta la sessione autenticata in precedenza dell'utente. La richiesta intersito falsa è nota anche come XSRF o CSRF.

Un esempio di attacco CSRF:

  1. Un utente accede a www.good-banking-site.example.com utilizzando l'autenticazione basata su form. Il server autentica l'utente e rilascia una risposta che include un'autenticazione cookie. Il sito è vulnerabile all'attacco perché considera attendibile qualsiasi richiesta ricevuta con un'autenticazione cookievalida.

  2. L'utente visita un sito dannoso, www.bad-crook-site.example.com.

    Il sito dannoso, www.bad-crook-site.example.com, contiene un modulo HTML simile all'esempio seguente:

    <h1>Congratulations! You're a Winner!</h1>
    <form action="https://www.good-banking-site.example.com/api/account" method="post">
        <input type="hidden" name="Transaction" value="withdraw" />
        <input type="hidden" name="Amount" value="1000000" />
        <input type="submit" value="Click to collect your prize!" />
    </form>
    

    Si noti che il modulo action invia i dati al sito vulnerabile, non al sito dannoso. Questa è la parte "cross-site" di CSRF.

  3. L'utente seleziona il pulsante invia. Il browser effettua la richiesta e include automaticamente l'autenticazione cookie per il dominio richiesto, www.good-banking-site.example.com.

  4. La richiesta viene eseguita sul www.good-banking-site.example.com server con il contesto di autenticazione dell'utente e può eseguire qualsiasi azione che un utente autenticato possa eseguire.

Oltre allo scenario in cui l'utente seleziona il pulsante per inviare il modulo, il sito dannoso potrebbe:

  • Eseguire uno script che invia automaticamente il modulo.
  • Inviare il modulo come richiesta AJAX.
  • Nascondere il modulo usando CSS.

Questi scenari alternativi non richiedono alcuna azione o input da parte dell'utente diverso da visitare inizialmente il sito dannoso.

L'uso di HTTPS non impedisce un attacco CSRF. Il sito dannoso può inviare una richiesta https://www.good-banking-site.example.com/ con la stessa facilità con cui può inviare una richiesta non sicura.

Alcuni attacchi usano endpoint che rispondono alle richieste GET, nel qual caso è possibile usare un tag immagine per eseguire l'azione. Questa forma di attacco è comune nei siti del forum che consentono immagini ma bloccano JavaScript. Le app che cambiano lo stato nelle richieste GET, in cui le variabili o le risorse vengono modificate, sono vulnerabili ad attacchi dannosi. Le richieste GET che cambiano lo stato non sono sicure. Una procedura consigliata consiste nel non modificare mai lo stato in una richiesta GET.

Gli attacchi CSRF sono possibili contro le app Web che usano cookie per l'autenticazione perché:

  • I browser archivia i cookie rilasciati da un'app Web.
  • I cookie archiviati includono cookie di sessione per gli utenti autenticati.
  • I browser inviano tutti i cookie associati a un dominio all'app Web ogni richiesta indipendentemente dalla modalità di generazione della richiesta all'app all'interno del browser.

Tuttavia, gli attacchi CSRF non sono limitati a sfruttare i cookie. Ad esempio, anche l'autenticazione di base e digest è vulnerabile. Dopo che un utente accede con l'autenticazione di base o digest, il browser invia automaticamente le credenziali fino al termine della sessione.

In questo contesto, la sessione fa riferimento alla sessione sul lato client durante la quale l'utente viene autenticato. Non è correlato alle sessioni lato server o al middleware della sessione ASP.NET Core.

Gli utenti possono proteggersi dalle vulnerabilità CSRF adottando precauzioni:

  • Disconnettersi dalle app Web al termine dell'uso.
  • Cancellare periodicamente i cookie del browser.

Tuttavia, le vulnerabilità CSRF sono fondamentalmente un problema con l'app Web, non con l'utente finale.

Nozioni fondamentali di autenticazione

Cookie-based authentication è una forma comune di autenticazione. I sistemi di autenticazione basati su token sono in continua crescita, in particolare per le applicazioni a pagina singola.

Quando un utente esegue l'autenticazione usando il nome utente e la password, viene rilasciato un token contenente un ticket di autenticazione. Il token può essere usato per l'autenticazione e l'autorizzazione. Il token viene archiviato come oggetto cookie inviato con ogni richiesta eseguita dal client. La generazione e la convalida di questo cookie vengono eseguite con il middleware di autenticazione cookie. Il middleware serializza il principale utente in un cookie crittografato. Nelle richieste successive, il middleware convalida il cookie, ricrea il principale e assegna il principale alla proprietà HttpContext.User.

Autenticazione basata su token

Quando un utente viene autenticato, viene rilasciato un token (non un token antiforgery). Il token contiene informazioni utente sotto forma di attestazioni o di un token di riferimento che indirizza l'app allo stato utente mantenuto all'interno dell'app. Quando un utente tenta di accedere a una risorsa che richiede l'autenticazione, il token viene inviato all'app con un'intestazione di autorizzazione aggiuntiva sotto forma di Bearer token. Questo approccio rende l'applicazione senza stato. In ogni richiesta successiva, il token viene passato nella richiesta di convalida lato server. Questo token non è crittografato, ma viene codificato. Nel server il token viene decodificato per accedere alle informazioni. Per inviare il token alle richieste successive, archiviare il token nella risorsa di archiviazione locale del browser. Posizionare un token nell'archiviazione locale del browser e recuperarlo e usarlo come token di connessione fornisce protezione dagli attacchi CSRF. Tuttavia, se l'app è vulnerabile all'inserimento di script tramite XSS o un file JavaScript esterno compromesso, un cyberattacker potrebbe recuperare qualsiasi valore dall'archiviazione locale e inviarlo a se stessi. ASP.NET Core codifica tutti gli output lato server dalle variabili per impostazione predefinita, riducendo il rischio di XSS. Se si esegue l'override di questo comportamento usando Html.Raw o codice personalizzato con input non attendibile, è possibile aumentare il rischio di XSS.

Non preoccuparsi della vulnerabilità CSRF se il token viene archiviato nella risorsa di archiviazione locale del browser. CSRF è un problema quando il token viene memorizzato in un cookie. Per altre informazioni, vedere l'esempio di codice SPA relativo al problema di GitHub che aggiunge due cookie.

Più app ospitate in un dominio

Gli ambienti di hosting condivisi sono vulnerabili all'hijacking della sessione, all'accesso CSRF e ad altri attacchi.

Anche se example1.contoso.net e example2.contoso.net sono host diversi, esiste una relazione di trust implicita tra gli host nel *.contoso.net dominio. Questa relazione di trust implicita consente agli host potenzialmente non attendibili di influire sui cookie degli altri (i criteri di stessa origine che regolano le richieste AJAX non si applicano necessariamente ai cookie HTTP).

Gli attacchi che sfruttano i cookie attendibili tra app ospitate nello stesso dominio possono essere impediti non condividendo domini. Quando ogni app è ospitata nel proprio dominio, non esiste alcuna relazione di trust implicita cookie da sfruttare.

Recupera le intestazioni dei metadati

I browser moderni allegano le intestazioni di richiesta Fetch Metadata — in particolare Sec-Fetch-Site — a ogni richiesta. Sec-Fetch-Site descrive la relazione tra l'origine che ha avviato la richiesta e l'origine richiesta: same-origin identifica una richiesta effettuata dal sito stesso, mentre same-site identifica cross-site le richieste avviate da un'altra origine. L'intestazione Origin contiene l'origine iniziale e funge da fallback per i browser che precedono il recupero dei metadati.

Sec-Fetch-Site e Origin sono intestazioni di richiesta vietate: il browser le imposta e il codice JavaScript eseguito in una pagina non può sovrascriverle né falsificarle. Ciò li rende un segnale affidabile per distinguere le richieste proprie di un sito da quelle tra siti diversi senza un token emesso dal server. La protezione CSRF automatica integrata in ASP.NET Core usa questo segnale per rifiutare i post di modulo tra siti non considerati esplicitamente attendibili.

Protezione CSRF automatica in ASP.NET Core

ASP.NET Core fornisce un middleware di protezione CSRF automatico abilitato per impostazione predefinita nelle app compilate con WebApplication.CreateBuilder. A differenza del sistema antiforgery basato su token, questo middleware non rilascia o convalida i token. Controlla invece le Sec-Fetch-Site intestazioni dei metadati e Originrecupera i metadati e registra un verdetto di convalida sulla richiesta. I componenti che elaborano i dati del modulo inviato applicano tale decisione, rifiutando gli invii di moduli cross-origin non esplicitamente attendibili.

Per la maggior parte delle app, non sono necessarie modifiche al codice: le richieste del browser dalla stessa origine, i metodi HTTP sicuri e i client non basati su browser (curl, da server a server, app per dispositivi mobili) continuano tutti a funzionare senza alcuna modifica. Il middleware interessa principalmente le app che accettano invii di moduli cross-origin da un browser, ad esempio un sito che invia un modulo a un'API su un'origine diversa. Questi scenari devono configurare CORS per dichiarare l'origine attendibile o rifiutare esplicitamente l'endpoint.

Questo middleware è aggiuntivo al sistema anti-contraffazione basato su token. Le due protezioni coesistono e possono essere entrambe attive nello stesso endpoint. Per un confronto di quando si applica ognuno di essi, vedere Interazione con l'antiforgeria basata su token.

Come funziona

Per ogni richiesta, il middleware valuta una catena breve di regole per raggiungere un verdetto, consentito o negato. I controlli vengono eseguiti in ordine e la prima corrispondenza vince:

  1. I metodi HTTP sicuri sono sempre consentiti.GET, HEAD, OPTIONS e TRACE le richieste vengono inoltrate. Ciò è conforme a RFC 9110 §9.2.1 ed è coerente con la regola consolidata da tempo secondo cui gli endpoint non dovrebbero modificare lo stato con GET.
  2. Sec-Fetch-Site: same-origin o Sec-Fetch-Site: none è consentito. I browser moderni inviano Sec-Fetch-Site su ogni richiesta. same-origin copre la normale navigazione e recupero in-app e none copre le richieste avviate direttamente dall'utente (digitando un URL, usando un segnalibro). Questo è il flusso di esecuzione del codice più comune: la maggior parte del traffico legittimo del browser passa di qui.
  3. È consentita un'origine attendibile da CORS. Se la richiesta contiene un'intestazione Origin e i criteri CORS risolti dell'endpoint considerano attendibile tale origine, la richiesta è consentita. Il middleware risolve il criterio allo stesso modo del middleware CORS: prima il criterio per endpoint da [EnableCors("name")], quindi il criterio predefinito registrato con AddDefaultPolicy. Vedi Allowing cross-origin clients per importanti limitazioni relative a questa regola.
  4. Qualsiasi altro Sec-Fetch-Site valore viene negato. Quando Sec-Fetch-Site è cross-site o same-site e l'origine non è attendibile tramite CORS, la richiesta viene negata.
  5. Nessun Sec-Fetch-Site, ma Origin è presente: il middleware confronta Origin con scheme://host[:port] costruito dalla richiesta. Se corrispondono, la richiesta è consentita; in caso contrario, viene negata. Questo è il percorso di fallback per i browser precedenti alla specifica Fetch Metadata (rilasciata ~2020).
  6. No Sec-Fetch-Site e no Origin: la richiesta è consentita. I browser inviano sempre almeno uno di questi su una richiesta di scrittura, quindi una richiesta mancante è quasi certamente un client non browser come curl, Postman, un'app per dispositivi mobili o un chiamante da server a server. CSRF è un vettore di attacco basato esclusivamente sul browser, quindi queste richieste vengono inoltrate.

Il middleware registra questo verdetto sulla richiesta anziché terminare la richiesta stessa. Per informazioni su come e quando un verdetto negato diventa una risposta HTTP 400 Bad Request , vedere Convalida posticipata.

Convalida posticipata

Il middleware non rifiuta una richiesta autonomamente. Registra invece il verdetto sulla IAntiforgeryValidationFeaturerichiesta, la stessa caratteristica usata dal sistema antiforgery basato su token, in cui un verdetto negato viene registrato come non valido. La richiesta continua lungo la pipeline. Un verdetto non valido diventa HTTP 400 Bad Request solo quando un componente che elabora i dati del modulo lo osserva. Questo differimento corrisponde al comportamento del sistema basato su token: il verdetto viene prodotto in anticipo ma applicato nel punto in cui viene utilizzato un modulo.

I componenti seguenti leggono IAntiforgeryValidationFeature e rifiutano una richiesta con 400 - Bad Request quando il verdetto registrato non è valido:

  • Azioni MVC protette dalla contraffazione.
  • Endpoint di API minimali che eseguono il binding di un parametro di un form.
  • Blazor Endpoint SSR.
  • Qualsiasi codice che legge direttamente il modulo di richiesta, che funge da backstop.

Ogni consumer verifica innanzitutto che un middleware antiforgery o CSRF sia stato effettivamente eseguito prima di considerare attendibile il verdetto, quindi una pipeline priva di entrambi i middleware non produce rifiuti errati.

Una conseguenza di questo modello è che un endpoint che non legge mai i dati del modulo viene eseguito anche quando il verdetto non è valido. Ad esempio, un endpoint API JSON che associa il corpo della richiesta ai dati JSON, oppure una routine di gestione che ignora il corpo della richiesta, non viene rifiutato automaticamente in caso di richiesta tra origini diverse. Il verdetto è ancora memorizzato in IAntiforgeryValidationFeature per il codice che vuole controllarlo, ma nulla lo impone. CSRF è un vettore di attacco basato su form ecookie, quindi gli endpoint che in genere non elaborano un modulo inviato dal browser non richiedono questo rifiuto. Gli endpoint che eseguono l'elaborazione dei moduli,Razor ovvero pagine, visualizzazioni MVC, Blazor SSR e binding di moduli API minimi, ottengono automaticamente la protezione.

Comportamento predefinito

Il middleware viene registrato automaticamente da WebApplication.CreateBuilder ed eseguito dopo l'autenticazione e l'autorizzazione. Convalida ogni richiesta usando l'implementazione registrata ICsrfProtection , che per impostazione predefinita applica le regole descritte in Come funziona. L'implementazione predefinita può essere sostituita; vedere Personalizzazione: implementare ICsrfProtection. Per disattivare completamente il middleware, vedere Disabilitazione globale.

Il risultato è che un'app minima con un endpoint di gestione dei moduli come quello seguente è già protetta:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapPost("/widgets", ([FromForm] Widget w) =>
    Results.Created($"/widgets/{w.Id}", w));

app.Run();

Un browser che effettua una richiesta di stessa origine POST /widgets raggiunge normalmente l'endpoint. Un browser in https://attacker.example.com che invia lo stesso modulo viene rifiutato con 400 - Bad Request quando l'endpoint esegue il binding del modulo, prima dell'esecuzione del corpo del gestore. Una curl richiesta senza Sec-Fetch-Site o Origin è consentita.

Poiché il rifiuto viene demandato ai consumer del form, un endpoint che non legge i dati del form, ad esempio un'API JSON che esegue il binding del corpo della richiesta dal JSON, non viene rifiutato automaticamente, anche in caso di richiesta cross-origin. Il risultato viene comunque registrato nella richiesta del codice che intende esaminarlo.

Il middleware si integra con il modello antiforgery esistente:

  • API minimali: La chiamata di .DisableAntiforgery() su un endpoint esclude tale endpoint da sia il middleware basato su token sia il middleware di protezione CSRF. Gli stessi metadati (IAntiforgeryMetadata { RequiresValidation = false }) vengono controllati da entrambi.
  • Controller e azioni MVC:[IgnoreAntiforgeryToken] esclude inoltre l'endpoint da entrambe le protezioni.

Consentire ai client di origine diversa

Lo scenario più comune che richiede un'azione è un client basato su browser che invia un modulo tra origini diverse, ad esempio un sito in https://app.contoso.com che invia un modulo a un'API in https://api.contoso.com. Tali post di modulo vengono negati per impostazione predefinita perché Sec-Fetch-Site è same-site o cross-site anziché same-origine il consumer del modulo impone tale verdetto con un oggetto 400 - Bad Request.

Il middleware CSRF non introduce il proprio elenco di attendibilità. Riutilizza la stessa policy CORS che il middleware CORS risolve per l'endpoint: se tale policy consente il/la Origin della richiesta, il middleware CSRF registra per la richiesta un esito di autorizzazione.

Il criterio viene selezionato per ciascun endpoint nel seguente ordine:

  1. [EnableCors("api")] (MVC) o .RequireCors("api") (Minimal API) → il criterio denominato "api".
  2. Nessun metadato CORS sull'endpoint → il criterio predefinito registrato con AddDefaultPolicy.
  3. Nessun criterio di corrispondenza (criteri denominati non registrati, nessun criterio predefinito o services.AddCors() mai chiamato) → nessuna relazione di trust derivata da CORS. Il middleware ricade nelle regole Sec-Fetch-Site e Origin-vs-Host.

Un esempio minimo che usa un criterio predefinito e un endpoint API minimo:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(policy =>
        policy.WithOrigins("https://app.contoso.com")
              .AllowAnyHeader()
              .AllowAnyMethod());
});

var app = builder.Build();

app.UseCors();

app.MapPost("/widgets", ([FromForm] Widget w) =>
    Results.Created($"/widgets/{w.Id}", w));

app.Run();

Per un criterio con nome su un singolo endpoint:

app.MapPost("/widgets", ([FromForm] Widget w) => Results.Created($"/widgets/{w.Id}", w))
   .RequireCors("api");

Avviso

AllowAnyOrigin non è intenzionalmente rispettato come segnale di attendibilità CSRF. AllowAnyOrigin significa "qualsiasi browser può leggere questa risorsa", che è un problema diverso da "qualsiasi origine può modificare lo stato per conto dell'utente". Considerando come attendibile AllowAnyOrigin questo middleware viene trasformato in un no-op per le scritture tra le origini. Le app che richiedono un criterio CORS con lettura pubblica in combinazione con scritture protette da CSRF devono elencare esplicitamente le origini attendibili per la scrittura con WithOrigins oppure escludere gli endpoint di scrittura se non si basano sull'autenticazione basata su cookie.

[DisableCors] su un endpoint non equivale a un’esclusione dal CSRF. Salta il passaggio di attendibilità derivato da CORS, e la richiesta deve comunque soddisfare le regole Sec-Fetch-Site e le regole Origin-vs-Host. Per disattivare la protezione CSRF, vedi Escludere un endpoint.

Per informazioni dettagliate sulla configurazione di CORS stesso—AddCors, AddDefaultPolicy, AddPolicy, WithOrigins e il resto dell'API del generatore di criteri—consulta Abilitare le richieste cross-origin (CORS) in ASP.NET Core.

Esclusione di un endpoint

Se un endpoint non è raggiungibile dal browser o è protetto da un meccanismo diverso da cookie, ad esempio un token bearer o una chiave API, escludilo singolarmente anziché disabilitare il middleware a livello globale.

API minime — chiama DisableAntiforgery sull'endpoint o sul gruppo:

app.MapPost("/api/webhook", (WebhookPayload p) => Results.Accepted())
   .DisableAntiforgery();

Controller MVC : si applicano [IgnoreAntiforgeryToken] all'azione o al controller:

[ApiController]
[Route("api/[controller]")]
[IgnoreAntiforgeryToken]
public class WebhookController : ControllerBase
{
    [HttpPost]
    public IActionResult Post([FromBody] WebhookPayload payload) => Accepted();
}

Entrambi gli approcci aggiungono IAntiforgeryMetadata { RequiresValidation = false } all'endpoint, che il middleware CSRF rispetta ignorando la convalida.

Avviso

Disattivare la protezione CSRF per un endpoint va fatto solo quando l'endpoint non è vulnerabile agli attacchi CSRF, ad esempio nel caso di endpoint che non possono essere chiamati da un browser o che sono protetti da autenticazione non-cookie, come token bearer o chiavi API. Non disabilitare la protezione CSRF sugli endpoint accessibili dal browser che si basano sui cookie per l'autenticazione.

Disabilitazione globale

Il middleware può essere disabilitato nell'intera app usando la DisableCsrfProtection chiave di configurazione. Questa è una scappatoia: è preferibile usare esclusioni a livello di singolo endpoint.

In appsettings.json:

{
  "DisableCsrfProtection": true
}

Oppure come variabile di ambiente:

ASPNETCORE_DisableCsrfProtection=true

Quando questa chiave è impostata su true, WebApplication ignora la registrazione del middleware nella pipeline. Il ICsrfProtection servizio rimane registrato, quindi tutto ciò che lo risolve direttamente continua a funzionare.

Avviso

Il middleware CSRF automatico soddisfa anche il requisito antiforgery per gli endpoint che richiedono la convalida, anche quando un'app non chiama app.UseAntiforgery(). Se un'app si basa sulla protezione antiforgery ma non chiama app.UseAntiforgery(), la disattivazione globale del middleware CSRF oppure l'esecuzione in un host che non è stato creato con WebApplication, in cui il middleware non viene aggiunto, lascia tali endpoint privi del middleware antiforgery. Una richiesta a tale endpoint genera quindi un'eccezione. Chiama app.UseAntiforgery() in quella configurazione.

Supporto del browser

Sec-Fetch-Site è supportato da tutte le versioni correnti di browser basati su Chromium, Firefox e Safari. Per una tabella di compatibilità ufficiale, consulta il riferimento MDN per Sec-Fetch-Site.

I browser meno recenti che precedono i metadati di recupero non inviano Sec-Fetch-Site. Per questi client, il middleware ricorre al confronto dell'intestazione Origin con lo schema e l'host della richiesta. I browser inviano Origin nelle richieste di scrittura cross-origin da molti anni, quindi questo meccanismo di fallback copre essenzialmente tutto il traffico proveniente dai browser meno recenti.

Client non browser—curl, Postman, app mobili, chiamanti server-to-server—in genere non inviano né Sec-Fetch-SiteOrigin. Tali richieste sono consentite perché CSRF è un vettore di attacco limitato ai browser che si basa sul fatto che il browser alleghi automaticamente credenziali implicite, come i cookie. Un client non browser che vuole attaccare l'API non ha bisogno di CSRF; può semplicemente chiamare l'API direttamente con le credenziali che possiede.

Personalizzazione: implementare ICsrfProtection

La logica decisionale è incapsulata dietro un’interfaccia con un solo metodo:

namespace Microsoft.AspNetCore.Antiforgery;

public interface ICsrfProtection
{
    ValueTask<CsrfProtectionResult> ValidateAsync(HttpContext context);
}

Per sostituire l'implementazione predefinita, registrare un singleton nell'inserimento delle dipendenze. Poiché il framework usa TryAddSingleton, una chiamata esplicita AddSingleton esegue l'override dell'impostazione predefinita:

builder.Services.AddSingleton<ICsrfProtection, AllowlistCsrfProtection>();

Un'implementazione personalizzata è utile quando il modello di attendibilità non rientra in CORS, ad esempio quando si preferisce un elenco di origini partner fisso o quando sono necessarie regole più rigorose:

using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Http;

public sealed class AllowlistCsrfProtection : ICsrfProtection
{
    private static readonly HashSet<string> SafeMethods =
        new(StringComparer.OrdinalIgnoreCase) { "GET", "HEAD", "OPTIONS", "TRACE" };

    private static readonly HashSet<string> TrustedOrigins =
        new(StringComparer.OrdinalIgnoreCase)
        {
            "https://app.contoso.com",
            "https://admin.contoso.com",
        };

    public ValueTask<CsrfProtectionResult> ValidateAsync(HttpContext context)
    {
        if (SafeMethods.Contains(context.Request.Method))
        {
            return ValueTask.FromResult(CsrfProtectionResult.Allowed());
        }

        var origin = context.Request.Headers.Origin.ToString();
        var allowed = !string.IsNullOrEmpty(origin) && TrustedOrigins.Contains(origin);

        return ValueTask.FromResult(
            allowed ? CsrfProtectionResult.Allowed() : CsrfProtectionResult.Denied());
    }
}

Il middleware continua a rispettare .DisableAntiforgery() / [IgnoreAntiforgeryToken] indipendentemente da quale implementazione sia registrata: la disattivazione esplicita viene gestita dal middleware stesso prima che venga chiamato ValidateAsync.

Interazione con il sistema antifalsificazione basato su token

Le due difese CSRF hanno come destinazione livelli diversi e sono progettate per coesistere. Condividono anche la stessa funzionalità di richiesta: entrambi registrano il risultato in IAntiforgeryValidationFeaturee i consumer del modulo applicano qualsiasi verdetto presente.

Aspect Basato su token AntiforgeryMiddleware Middleware automatico per la protezione CSRF
Presentazione ASP.NET Core 2,0+ .NET 11
Activation Acconsentire esplicitamente tramite app.UseAntiforgery() (o in modo implicito daAddMvc / MapRazorPages / AddRazorComponents ) Inserito automaticamente da WebApplication.CreateBuilder
Convalida Token sincronizzato (campo del modulo + coppia cookie) Sec-Fetch-Site / Origin intestazioni
Requires Panoramica della protezione dei dati di ASP.NET Core per la crittografia dei token Nessun token, nessun stato
Ambito del browser Tutti i browser che inviano cookie Tutti i browser moderni; Origin soluzione di riserva per i browser legacy
Disattivazione per endpoint .DisableAntiforgery() / [IgnoreAntiforgeryToken] Stesso: entrambi rispettano gli stessi metadati

Il middleware basato su token protegge in modo specifico dal modello di attacco CSRF classico in cui un sito dannoso attiva un modulo POST per un sito vulnerabile usando i cookie di ambiente dell'utente. Il middleware CSRF automatico risolve la stessa minaccia a livello HTTP usando i metadati forniti dal browser. Entrambi possono essere attivi nello stesso endpoint e molte app trarranno vantaggio dalla difesa in profondità:

  • Razor Le app Pages, MVC e Blazor SSR che usano già il sistema di token ottengono un controllo basato su intestazione eseguito prima della convalida del token, senza modificare il flusso del token.
  • Le app Minimal API che eseguono il binding dei moduli usufruiscono di un comportamento predefinito utile senza dover chiamare app.UseAntiforgery() o passare IAntiforgery negli endpoint.
  • Le API chiamate da SPA di origine diversa possono basarsi su questo middleware combinato con un'allowlist CORS e fare completamente a meno del sistema di token se l'API non serve mai moduli HTML.

Il middleware CSRF automatico sostituisce il sistema basato su token in molti scenari, perché entrambi proteggono gli stessi endpoint di gestione dei moduli. Mantenere il sistema basato su token quando:

  • L'app deve supportare browser che non inviano Sec-Fetch-Site. Vedere Supporto del browser.
  • L'app usa IAntiforgeryAdditionalDataProvider per trasferire e recuperare dati aggiuntivi all'interno del token.
  • Un requisito di verifica della sicurezza o di conformità specifica la difesa dei token come livello indipendente.

Per informazioni dettagliate sul sistema basato su token, tra cui l'integrazione dei moduli, i flussi AJAX, la configurazione tramite AntiforgeryOptionse IAntiforgery le API, vedere Antiforgery in ASP.NET Core.

La convalida dei token ha la precedenza

Quando un'app chiama app.UseAntiforgery(), il middleware basato su token viene eseguito dopo il middleware CSRF automatico. Il middleware del token cancella qualsiasi verdetto registrato dal middleware CSRF e lo sostituisce con il risultato della convalida del token. Il risultato del token è autorevole:

  • Una richiesta che il middleware CSRF ha contrassegnato come non valida diventa valida se include un token valido.
  • Una richiesta consentita dal middleware CSRF è contrassegnata come non valida se il suo token è mancante o non valido.

Questo ordinamento significa che le app che usano il sistema di token presentano lo stesso comportamento end-to-end che avevano prima che esistesse il middleware automatico, mentre le app che non usano i token si rimettono al verdetto del middleware CSRF.

Blazor rendering lato server statico

Blazor Gli endpoint di rendering statico lato server (SSR) partecipano allo stesso modello differito. L'endpoint Components Razor si basa sul verdetto registrato su IAntiforgeryValidationFeature dal middleware a monte e restituisce 400 - Bad Request per un invio di modulo solo quando tale verdetto non è valido. L'endpoint non convalida più la richiesta stessa.

Il comportamento dipende dal middleware eseguito:

  • Le app che chiamano app.UseAntiforgery() sono invariate. Il middleware basato su token valida ogni richiesta e i token antifalsificazione vengono generati per i moduli sottoposti a rendering, come in precedenza.
  • Le app che non chiamano app.UseAntiforgery() sono protette dal middleware CSRF automatico. In tale configurazione l'endpoint ignora la generazione di token antiforgery perché non è presente alcun middleware del token per convalidare un token in una richiesta successiva.

Si tratta di una modifica del comportamento per l'SSR statico, che in precedenza rimuoveva app.UseAntiforgery(): ora è protetto dal middleware CSRF invece di essere lasciato privo di protezione e non emette più token antiforgery. Per indicazioni sulla migrazione, vedere Eseguire la migrazione da ASP.NET Core in .NET 10 a ASP.NET Core in .NET 11. Per la notifica formale della modifica incompatibile, vedere Blazor il rendering lato server rimanda la convalida antifalsificazione al middleware.

Troubleshooting

Sintomo: Le richieste dalla stessa origine provenienti da un browser hanno esito positivo, ma gli invii di moduli cross-origin restituiscono 400 - Bad Request con corpo vuoto.

Causa: Il middleware CSRF ha registrato una valutazione non valida per la richiesta cross-origin e un componente per l'elaborazione dei moduli, ad esempio un'azione MVC, un binding di moduli in Minimal API o un invio di moduli SSR Blazor, ha applicato tale valutazione con un 400 - Bad Request. Si tratta del comportamento predefinito previsto per gli endpoint che elaborano i moduli.

Risoluzione: Scegliere una delle opzioni seguenti, a seconda dello scenario:

Diagnosi: Il middleware registra ogni verdetto non valido a Debug livello inferiore alla categoria Microsoft.AspNetCore.Antiforgery.CsrfProtectionMiddleware con il nome CsrfValidationFaileddell'evento . Abilitare la Debug registrazione per la categoria in appsettings.Development.json:

{
  "Logging": {
    "LogLevel": {
      "Microsoft.AspNetCore.Antiforgery.CsrfProtectionMiddleware": "Debug"
    }
  }
}

Un verdetto registrato viene quindi visualizzato nel log come:

dbug: Microsoft.AspNetCore.Antiforgery.CsrfProtectionMiddleware[1]
      Cross-origin CSRF protection marked request POST /widgets from origin 'https://attacker.example.com' as invalid.

Riprodurre in locale: Usa curl con un'intestazione Origin esplicita per simulare una richiesta del browser tra origini diverse verso un endpoint di modulo:

curl -i -X POST https://localhost:{PORT}/widgets \
     -H "Origin: https://attacker.example.com" \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "name=test"

Sostituire {PORT} con la porta HTTPS locale dell'app. Il 400 - Bad Request viene osservato perché l'endpoint collega il modulo, che impone il verdetto registrato. Un endpoint non in formato restituisce la risposta normale perché nulla legge il verdetto. Senza l'intestazione Origin, la stessa richiesta è comunque consentita perché anche curl non invia Sec-Fetch-Site e una richiesta priva di entrambe le intestazioni viene considerata come proveniente da un client non browser.

Il sistema antiforgerato basato su token descritto nel resto di questo articolo precede questo middleware e rimane disponibile. Per la maggior parte delle app, la protezione automatica è sufficiente da sola. Per indicazioni su quando mantenere il sistema basato su token e su come eseguire la migrazione, vedere Eseguire la migrazione da ASP.NET Core in .NET 10 a ASP.NET Core in .NET 11.

Antifalsificazione in ASP.NET Core

Avviso

ASP.NET Core implementa l'antiforgeria usando ASP.NET Core Data Protection. Lo stack di protezione dati deve essere configurato per funzionare in una server farm. Per altre informazioni, vedere Configurazione della protezione dei dati.

Il middleware antiforgery viene aggiunto al contenitore di Dependency Injection quando viene chiamata una delle API seguenti in Program.cs:

Per ulteriori informazioni, vedere Antiforgery con API minime.

FormTagHelper inserisce token antifalsificazione negli elementi del modulo HTML. Il seguente markup in un file Razor genera automaticamente token anti-contraffazione.

<form method="post">
    <!-- ... -->
</form>

Analogamente, IHtmlHelper.BeginForm genera token antifalsificazione per impostazione predefinita se il metodo del form non è GET.

La generazione automatica di token antiforgery per gli elementi del modulo HTML si verifica quando il <form> tag contiene l'attributo method="post" e uno dei seguenti è true:

  • L'attributo action è vuoto (action="").
  • L'attributo action non viene fornito (<form method="post">).

La generazione automatica di token antiforgery per gli elementi del modulo HTML può essere disabilitata:

  • Disabilitare in modo esplicito i token antifalsificazione con l'attributo asp-antiforgery:

    <form method="post" asp-antiforgery="false">
        <!-- ... -->
    </form>
    
  • L'elemento del modulo è disattivato dagli helper tag usando il simbolo di disattivazione esplicita per gli helper tag:

    <!form method="post">
        <!-- ... -->
    </!form>
    
  • Rimuovere l'oggetto FormTagHelper dalla visualizzazione. L'oggetto FormTagHelper può essere rimosso da una visualizzazione aggiungendo la direttiva seguente alla visualizzazione Razor.

    @removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
    

Nota

Razor Le pagine vengono protette automaticamente da XSRF/CSRF. Per altre informazioni, vedere XSRF/CSRF e Razor Pages.

L'approccio più comune alla protezione dagli attacchi CSRF consiste nell'usare lo schema token di sincronizzazione (STP). STP viene usato quando l'utente richiede una pagina con dati del modulo:

  1. Il server invia un token associato all'identità dell'utente corrente al client.
  2. Il client invia il token al server per la verifica.
  3. Se il server riceve un token che non corrisponde all'identità dell'utente autenticato, la richiesta viene rifiutata.

Il token è univoco e imprevedibile. Il token può essere usato anche per garantire una sequenziazione corretta di una serie di richieste ( ad esempio, verificando la sequenza di richiesta di: pagina 1 > pagina 2 > pagina 3). Tutti i form nei modelli di ASP.NET Core MVC e nelle pagine Razor generano token antiforgery. La coppia di esempi di visualizzazione seguente genera token antiforgery:

<form asp-action="Index" asp-controller="Home" method="post">
    <!-- ... -->
</form>

@using (Html.BeginForm("Index", "Home"))
{
    <!-- ... -->
}

Aggiungere in modo esplicito un token antiforgery a un elemento <form> senza usare Tag Helper con l'helper HTML @Html.AntiForgeryToken.

<form asp-action="Index" asp-controller="Home" method="post">
    @Html.AntiForgeryToken()

    <!-- ... -->
</form>

In ognuno dei casi precedenti, ASP.NET Core aggiunge un campo modulo nascosto simile all'esempio seguente:

<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">

ASP.NET Core include tre filtri per l'uso di token antiforgery:

Anticontraffazione con AddControllers

La chiamata AddControllers non attiva i token antiforgery. AddControllersWithViews deve essere chiamato per ottenere il supporto integrato per i token antiforgery.

Più schede del browser e modello di token del programma di sincronizzazione

Non sono supportate più schede aperte con accesso come utenti diversi o una anonima.

Configurare l'antifalsificazione con AntiforgeryOptions

Personalizzare AntiforgeryOptions nel file Program dell'app

builder.Services.AddAntiforgery(options =>
{
    // Set Cookie properties using CookieBuilder properties†.
    options.FormFieldName = "AntiforgeryFieldname";
    options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
    options.SuppressXFrameOptionsHeader = false;
});

Impostare le proprietà antiforgery cookie usando le proprietà della classe CookieBuilder, come illustrato nella tabella seguente.

Opzione Descrizione
Cookie Stabilisce le impostazioni utilizzate per creare i cookie antifalsificazione.
FormFieldName Nome del campo modulo nascosto utilizzato dal sistema antiforgery per eseguire il rendering dei token antiforgery nelle visualizzazioni.
HeaderName Il nome dell'intestazione utilizzata dal sistema anti-forgery. Se null, il sistema considera solo i dati del modulo.
SuppressXFrameOptionsHeader Specifica se eliminare la generazione dell'intestazione X-Frame-Options . Per impostazione predefinita, l'intestazione viene generata con il valore "SAMEORIGIN". Il valore predefinito è false.

Alcuni browser non consentono agli endpoint non sicuri di impostare cookie con un flag "sicuro" o sovrascrivere i cookie il cui flag "sicuro" è impostato (per altre informazioni, vedere Deprecate modification of 'secure' cookies from non-secure origin). Poiché la combinazione di endpoint sicuri e non sicuri è uno scenario comune nelle app, ASP.NET Core alleggerisce la restrizione sulla politica di sicurezza per alcuni cookie, come l'antiforgery cookie, impostando il cookie di SecurePolicy su CookieSecurePolicy.None. Anche se un utente malintenzionato ruba un'antiforgeria , deve anche rubare il token antiforgery cookieche viene in genere inviato tramite un campo modulo (più comune) o un'intestazione di richiesta separata (meno comune) più l'autenticazione cookie. I cookie correlati all'autenticazione o all'autorizzazione usano criteri più efficaci rispetto CookieSecurePolicy.Nonea .

Facoltativamente, è possibile proteggere l'antiforgeria cookie in ambienti nonDevelopment usando SSL (Secure Sockets Layer), solo su HTTPS, con l'impostazione della proprietà seguente AntiforgeryOptions.Cookie nel file dell'app Program :

if (!builder.Environment.IsDevelopment())
{
    builder.Services.AddAntiforgery(o =>
    {
        o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    });
}

Per ulteriori informazioni, vedere CookieAuthenticationOptions.

Generare token antiforgery con IAntiforgery

IAntiforgery fornisce l'API per configurare le funzionalità antiforgery. IAntiforgery può essere richiesto in Program.cs tramite WebApplication.Services. L'esempio seguente utilizza un middleware collegato alla pagina iniziale dell'app per generare un token antifrode e inviarlo nella risposta come cookie:

app.UseRouting();

app.UseAuthorization();

var antiforgery = app.Services.GetRequiredService<IAntiforgery>();

app.Use((context, next) =>
{
    var requestPath = context.Request.Path.Value;

    if (string.Equals(requestPath, "/", StringComparison.OrdinalIgnoreCase)
        || string.Equals(requestPath, "/index.html", StringComparison.OrdinalIgnoreCase))
    {
        var tokenSet = antiforgery.GetAndStoreTokens(context);
        context.Response.Cookies.Append("XSRF-TOKEN", tokenSet.RequestToken!,
            new CookieOptions { HttpOnly = false });
    }

    return next(context);
});

Nell'esempio precedente viene impostato un cookie denominato XSRF-TOKEN. Il client può leggere questo cookie e specificarne il valore come intestazione collegata alle richieste AJAX. Ad esempio, Angular include la protezione XSRF integrata che legge un cookie denominato XSRF-TOKEN per impostazione predefinita.

Richiedi convalida antifalsificazione

Il filtro di azione ValidateAntiForgeryToken può essere applicato a una singola azione, a un controller o a livello globale. Le richieste effettuate alle azioni con questo filtro applicato vengono bloccate a meno che la richiesta non includa un token antiforgery valido:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
    // ...

    return RedirectToAction();
}

L'attributo ValidateAntiForgeryToken richiede un token per le richieste ai metodi di azione contrassegnati, incluse le richieste HTTP GET. Se l'attributo ValidateAntiForgeryToken viene applicato attraverso i controller dell'app, può essere sovrascritto con l'attributo IgnoreAntiforgeryToken.

Convalidare automaticamente i token antiforgery solo per metodi HTTP non sicuri

Anziché applicare l'attributo ValidateAntiForgeryToken a livello generale per poi eseguirne l'override con gli attributi IgnoreAntiforgeryToken, è possibile usare l'attributo AutoValidateAntiforgeryToken. Questo attributo funziona in modo identico all'attributo ValidateAntiForgeryToken , ad eccezione del fatto che non richiede token per le richieste effettuate usando i metodi HTTP seguenti:

  • GET
  • HEAD
  • OPZIONI
  • TRACE

È consigliabile l'uso di AutoValidateAntiforgeryToken in modo ampio per scenari non API. Questo attributo garantisce che le azioni POST siano protette per impostazione predefinita. L'alternativa consiste nell'ignorare i token antiforgery per impostazione predefinita, a meno che ValidateAntiForgeryToken venga applicato ai singoli metodi di azione. In questo scenario è più probabile che un metodo di azione POST venga lasciato non protetto per errore, lasciando l'app vulnerabile agli attacchi CSRF. Tutti i POST devono inviare il token antiforgery.

Le API non hanno un meccanismo automatico per l'invio dellacookie parte non del token. L'implementazione dipende probabilmente dall'implementazione del codice client. Di seguito sono riportati alcuni esempi:

Esempio a livello di classe:

[AutoValidateAntiforgeryToken]
public class HomeController : Controller

Esempio globale:

builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});

Sovrascrivere gli attributi antiforgery globali o del controller

Il filtro IgnoreAntiforgeryToken viene usato per eliminare la necessità di un token antiforgery per una determinata azione (o controller). Quando applicato, questo filtro sovrascrive i filtri ValidateAntiForgeryToken e AutoValidateAntiforgeryToken specificati ad un livello superiore (a livello globale o in un controller).

[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
    // ...

    return RedirectToAction();
}

Aggiornare i token dopo l'autenticazione

I token devono essere aggiornati dopo l'autenticazione dell'utente reindirizzando l'utente a una pagina di visualizzazione o Razor pagine.

JavaScript, AJAX e SPA

Nelle app tradizionali basate su HTML, i token antiforgery vengono passati al server tramite campi modulo nascosti. Nelle app moderne basate su JavaScript e nelle applicazioni a pagina singola, molte richieste vengono effettuate programmaticamente. Queste richieste AJAX possono usare altre tecniche, ad esempio intestazioni di richiesta o cookie, per inviare il token.

Se i cookie vengono usati per archiviare i token di autenticazione e per autenticare le richieste API nel server, CSRF è un potenziale problema. Se l'archiviazione locale viene usata per archiviare il token, la vulnerabilità CSRF potrebbe essere mitigata perché i valori dell'archiviazione locale non vengono inviati automaticamente al server con ogni richiesta. L'uso dell'archiviazione locale per archiviare il token antiforgery nel client e inviare il token come intestazione di richiesta è un approccio consigliato.

Blazor

Per ulteriori informazioni, vedere autenticazione e autorizzazione di ASP.NET CoreBlazor.

JavaScript

Usando JavaScript con visualizzazioni, il token può essere creato usando un servizio dall'interno della visualizzazione. Inserire il IAntiforgery servizio nella visualizzazione e chiamare GetAndStoreTokens:

@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery

@{
    ViewData["Title"] = "JavaScript";

    var requestToken = Antiforgery.GetAndStoreTokens(Context).RequestToken;
}

<input id="RequestVerificationToken" type="hidden" value="@requestToken" />

<button id="button" class="btn btn-primary">Submit with Token</button>
<div id="result" class="mt-2"></div>

@section Scripts {
<script>
    document.addEventListener("DOMContentLoaded", () => {
        const resultElement = document.getElementById("result");

        document.getElementById("button").addEventListener("click", async () => {

            const response = await fetch("@Url.Action("FetchEndpoint")", {
                method: "POST",
                headers: {
                    RequestVerificationToken:
                        document.getElementById("RequestVerificationToken").value
                }
            });

            if (response.ok) {
                resultElement.innerText = await response.text();
            } else {
                resultElement.innerText = `Request Failed: ${response.status}`
            }
        });
    });
</script>
}

L'esempio precedente usa JavaScript per leggere il valore del campo nascosto per l'intestazione POST AJAX.

Questo approccio elimina la necessità di gestire direttamente l'impostazione dei cookie dal server o di leggerli dal client. Tuttavia, quando non è possibile inserire il servizio IAntiforgery, utilizzare JavaScript per accedere ai token nei cookie.

  • I token di accesso in una richiesta aggiuntiva al server, di solito in genere same-origin.
  • Utilizzare il contenuto di cookie per creare un'intestazione con il valore del token.

Supponendo che lo script invii il token in un'intestazione di richiesta denominata X-XSRF-TOKEN, configurare il servizio antiforgery per cercare l'intestazione X-XSRF-TOKEN :

builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");

L'esempio seguente aggiunge un endpoint protetto che scrive il token di richiesta in un codice JavaScript leggibile cookie:

app.UseAuthorization();
app.MapGet("antiforgery/token", (IAntiforgery forgeryService, HttpContext context) =>
{
    var tokens = forgeryService.GetAndStoreTokens(context);
    context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken!,
            new CookieOptions { HttpOnly = false });

    return Results.Ok();
}).RequireAuthorization();

L'esempio seguente usa JavaScript per effettuare una richiesta AJAX per ottenere il token e effettuare un'altra richiesta con l'intestazione appropriata:

var response = await fetch("/antiforgery/token", {
    method: "GET",
    headers: { "Authorization": authorizationToken }
});

if (response.ok) {
    // https://developer.mozilla.org/docs/web/api/document/cookie
    const xsrfToken = document.cookie
        .split("; ")
        .find(row => row.startsWith("XSRF-TOKEN="))
        .split("=")[1];

    response = await fetch("/JavaScript/FetchEndpoint", {
        method: "POST",
        headers: { "X-XSRF-TOKEN": xsrfToken, "Authorization": authorizationToken }
    });

    if (response.ok) {
        resultElement.innerText = await response.text();
    } else {
        resultElement.innerText = `Request Failed: ${response.status}`
    }
} else {    
    resultElement.innerText = `Request Failed: ${response.status}`
}

Nota

Quando il token antiforgery viene fornito sia nell'intestazione della richiesta che nel contenuto del modulo, viene convalidato solo il token nell'intestazione.

Antiforgery con API minime

Chiama AddAntiforgery e UseAntiforgery(IApplicationBuilder) per registrare i servizi antiforgery in DI. I token antiforgery vengono usati per mitigare attacchi di falsificazione della richiesta tra siti.

var builder = WebApplication.CreateBuilder();

builder.Services.AddAntiforgery();

var app = builder.Build();

app.UseAntiforgery();

app.MapGet("/", () => "Hello World!");

app.Run();

Il middleware antiforgery:

Il token antiforgery viene convalidato solo se:

  • L'endpoint contiene i metadati che implementano IAntiforgeryMetadata in cui RequiresValidation=true.
  • Il metodo HTTP associato all'endpoint è un metodo HTTP pertinente di tipo POST, PUT o PATCH.
  • La richiesta è associata a un endpoint valido.

Il middleware antiforgery non interrompe la pipeline delle richieste. Il codice endpoint viene sempre eseguito, anche se la convalida del token non riesce. Per osservare il risultato della convalida del token, risolvere IAntiforgeryValidationFeature da HttpContext.Features e controllarne la proprietà IsValid o la proprietà Error per i dettagli dell'errore. Questo approccio è utile quando gli endpoint richiedono una gestione personalizzata per la convalida antiforgery non riuscita.

Nota: se abilitato manualmente, il middleware antiforgery deve essere eseguito dopo il middleware di autenticazione e autorizzazione per impedire la lettura dei dati del modulo quando l'utente non è autenticato.

Per impostazione predefinita, le Minimal APIs che accettano i dati del modulo richiedono la convalida del token antiforgery e non vengono eseguite prima che il codice dell'applicazione venga eseguito se la convalida antiforgery non è riuscita.

Si consideri il metodo seguente GenerateForm :

public static string GenerateForm(string action, 
    AntiforgeryTokenSet token, bool UseToken=true)
{
    string tokenInput = "";
    if (UseToken)
    {
        tokenInput = $@"<input name=""{token.FormFieldName}""
                         type=""hidden"" value=""{token.RequestToken}"" />";
    }

    return $@"
    <html><body>
        <form action=""{action}"" method=""POST"" enctype=""multipart/form-data"">
            {tokenInput}
            <input type=""text"" name=""name"" />
            <input type=""date"" name=""dueDate"" />
            <input type=""checkbox"" name=""isCompleted"" />
            <input type=""submit"" />
        </form>
    </body></html>
";
}

Il codice precedente ha tre argomenti, l'azione, il token antiforgery e un bool che indica se il token deve essere usato.

Si consideri l'esempio seguente:

using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder();

builder.Services.AddAntiforgery();

var app = builder.Build();

app.UseAntiforgery();

// Pass token
app.MapGet("/", (HttpContext context, IAntiforgery antiforgery) =>
{
    var token = antiforgery.GetAndStoreTokens(context);
    return Results.Content(MyHtml.GenerateForm("/todo", token), "text/html");
});

// Don't pass a token, fails
app.MapGet("/SkipToken", (HttpContext context, IAntiforgery antiforgery) =>
{
    var token = antiforgery.GetAndStoreTokens(context);
    return Results.Content(MyHtml.GenerateForm("/todo",token, false ), "text/html");
});

// Post to /todo2. DisableAntiforgery on that endpoint so no token needed.
app.MapGet("/DisableAntiforgery", (HttpContext context, IAntiforgery antiforgery) =>
{
    var token = antiforgery.GetAndStoreTokens(context);
    return Results.Content(MyHtml.GenerateForm("/todo2", token, false), "text/html");
});

app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));

app.MapPost("/todo2", ([FromForm] Todo todo) => Results.Ok(todo))
                                                .DisableAntiforgery();

app.Run();

class Todo
{
    public required string Name { get; set; }
    public bool IsCompleted { get; set; }
    public DateTime DueDate { get; set; }
}

public static class MyHtml
{
    public static string GenerateForm(string action, 
        AntiforgeryTokenSet token, bool UseToken=true)
    {
        string tokenInput = "";
        if (UseToken)
        {
            tokenInput = $@"<input name=""{token.FormFieldName}""
                             type=""hidden"" value=""{token.RequestToken}"" />";
        }

        return $@"
        <html><body>
            <form action=""{action}"" method=""POST"" enctype=""multipart/form-data"">
                {tokenInput}
                <input type=""text"" name=""name"" />
                <input type=""date"" name=""dueDate"" />
                <input type=""checkbox"" name=""isCompleted"" />
                <input type=""submit"" />
            </form>
        </body></html>
    ";
    }
}

Nel codice precedente, invia a:

  • /todo richiede un token antiforgery valido.
  • /todo2 non richiedono un token antiforgery valido quando DisableAntiforgery è chiamato.
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));

app.MapPost("/todo2", ([FromForm] Todo todo) => Results.Ok(todo))
                                                .DisableAntiforgery();

Avviso

La chiamata .DisableAntiforgery() disabilita la protezione CSRF (Cross-Site Request Forgery) per l'endpoint. Questa operazione deve essere usata solo quando un endpoint non è vulnerabile agli attacchi CSRF, ad esempio:

  • Endpoint che non sono chiamabili da un browser (ad esempio, API interne)
  • Endpoint protetti con autenticazione noncookie basata (ad esempio, token di connessione o chiavi API)
  • Endpoint interni o dell'infrastruttura che non dipendono dai cookie utente

Non disabilitare la convalida antifrode per gli endpoint accessibili dal browser che si basano sui cookie per l'autenticazione o che elaborano i dati dei moduli inviati dagli utenti, in quanto espone l'applicazione agli attacchi CSRF.

Esegui un POST a:

  • /todo dal modulo generato dall'endpoint / ha esito positivo perché il token antiforgery è valido.
  • /todo dal modulo generato da /SkipToken fallisce perché l'antifalsificazione non è inclusa.
  • /todo2 dal modulo generato dall'endpoint ha esito positivo perché l'antiforgery /DisableAntiforgery non è obbligatorio.
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));

app.MapPost("/todo2", ([FromForm] Todo todo) => Results.Ok(todo))
                                                .DisableAntiforgery();

Quando un modulo viene inviato senza un token antiforgery valido:

  • Nell'ambiente Development viene generata un'eccezione.
  • Nell'ambiente Production viene registrato un messaggio.

Limitazioni dei metodi HTTP e interazione con HttpMethodOverrideMiddleware

Per il percorso antiforgery basato su middleware, AntiforgeryMiddleware e UseAntiforgery() convalidano i token antiforgery solo per le richieste HTTP POST, PUT e PATCH. Altri metodi HTTP, ad esempio DELETE, non vengono convalidati automaticamente.

Per convalidare i token antiforgery per altri metodi HTTP, risolvere IAntiforgery dal contenitore DI e chiamare ValidateRequestAsync o IsRequestValidAsync esplicitamente:

app.MapDelete("/item/{id}", async (int id, IAntiforgery antiforgery, HttpContext context) =>
{
    await antiforgery.ValidateRequestAsync(context);
    // Process the DELETE request
});

Avviso

Quando HttpMethodOverrideMiddleware è configurato con FormFieldName (modalità campo del modulo) e posizionato prima di AntiforgeryMiddleware, è possibile forzare una richiesta POST a DELETE (o a un altro metodo non convalidato). Poiché AntiforgeryMiddleware convalida solo POST, PUT e PATCH, la richiesta sottoposta a override ignora la convalida antiforgery.

Per proteggere questi endpoint:

  • È preferibile posizionare HttpMethodOverrideMiddleware dopo la convalida anti-contraffazione quando la pipeline lo consente.
  • Evitare sovrascritture dei campi del modulo per gli endpoint che si basano sulla convalida anti-contraffazione.
  • Se l'override del campo del modulo deve essere applicato per primo, convalidare esplicitamente il token antiforgery usando IAntiforgery.ValidateRequestAsync.

Per informazioni dettagliate sulla configurazione, vedere ASP.NET Core middleware.

autenticazione Windows e i cookie antifalsificazione

Quando si usa l'autenticazione di Windows, gli endpoint dell'applicazione devono essere protetti dagli attacchi CSRF nello stesso modo usato per i cookie. Il browser invia in modo implicito il contesto di autenticazione al server e agli endpoint devono essere protetti dagli attacchi CSRF.

Estendere il sistema anti-contraffazione

Il tipo IAntiforgeryAdditionalDataProvider permette agli sviluppatori di espandere il comportamento del sistema anti-CSRF trasferendo dati aggiuntivi in ogni token. Il GetAdditionalData metodo viene chiamato ogni volta che viene generato un token di campo e il valore restituito viene incorporato all'interno del token generato. Un implementatore può restituire un timestamp, un nonce o qualsiasi altro valore e quindi chiamare ValidateAdditionalData per convalidare questi dati quando il token viene convalidato. Il nome utente del client è già incorporato nei token generati, quindi non è necessario includere queste informazioni. Se un token include dati supplementari ma non IAntiForgeryAdditionalDataProvider è configurato, i dati supplementari non vengono convalidati.

Risorse aggiuntive

La falsificazione di richiesta intersito (nota anche come XSRF o CSRF) è un attacco contro le applicazioni ospitate sul Web in cui un'applicazione Web dannosa può influenzare l'interazione tra il browser del client e un'applicazione Web che considera attendibile quel browser. Questi attacchi sono possibili perché i Web browser inviano automaticamente alcuni tipi di token di autenticazione con ogni richiesta a un sito Web. Questa forma di exploit è nota anche come attacco con un clic o guida di sessione perché l'attacco sfrutta la sessione autenticata in precedenza dell'utente.

Un esempio di attacco CSRF:

  1. Un utente accede a www.good-banking-site.example.com utilizzando l'autenticazione basata su form. Il server autentica l'utente e rilascia una risposta che include un'autenticazione cookie. Il sito è vulnerabile all'attacco perché considera attendibile qualsiasi richiesta ricevuta con un'autenticazione cookievalida.

  2. L'utente visita un sito dannoso, www.bad-crook-site.example.com.

    Il sito dannoso, www.bad-crook-site.example.com, contiene un modulo HTML simile all'esempio seguente:

    <h1>Congratulations! You're a Winner!</h1>
    <form action="https://www.good-banking-site.example.com/api/account" method="post">
        <input type="hidden" name="Transaction" value="withdraw" />
        <input type="hidden" name="Amount" value="1000000" />
        <input type="submit" value="Click to collect your prize!" />
    </form>
    

    Si noti che il modulo action invia i dati al sito vulnerabile, non al sito dannoso. Questa è la parte "cross-site" di CSRF.

  3. L'utente seleziona il pulsante invia. Il browser effettua la richiesta e include automaticamente l'autenticazione cookie per il dominio richiesto, www.good-banking-site.example.com.

  4. La richiesta viene eseguita sul www.good-banking-site.example.com server con il contesto di autenticazione dell'utente e può eseguire qualsiasi azione che un utente autenticato possa eseguire.

Oltre allo scenario in cui l'utente seleziona il pulsante per inviare il modulo, il sito dannoso potrebbe:

  • Eseguire uno script che invia automaticamente il modulo.
  • Inviare il modulo come richiesta AJAX.
  • Nascondere il modulo usando CSS.

Questi scenari alternativi non richiedono alcuna azione o input da parte dell'utente diverso da visitare inizialmente il sito dannoso.

L'uso di HTTPS non impedisce un attacco CSRF. Il sito dannoso può inviare una richiesta https://www.good-banking-site.example.com/ con la stessa facilità con cui può inviare una richiesta non sicura.

Alcuni attacchi usano endpoint che rispondono alle richieste GET, nel qual caso è possibile usare un tag immagine per eseguire l'azione. Questa forma di attacco è comune nei siti del forum che consentono immagini ma bloccano JavaScript. Le app che cambiano lo stato nelle richieste GET, in cui le variabili o le risorse vengono modificate, sono vulnerabili ad attacchi dannosi. Le richieste GET che cambiano lo stato non sono sicure. Una procedura consigliata consiste nel non modificare mai lo stato in una richiesta GET.

Gli attacchi CSRF sono possibili contro le app Web che usano cookie per l'autenticazione perché:

  • I browser archivia i cookie rilasciati da un'app Web.
  • I cookie archiviati includono cookie di sessione per gli utenti autenticati.
  • I browser inviano tutti i cookie associati a un dominio all'app Web ogni richiesta indipendentemente dalla modalità di generazione della richiesta all'app all'interno del browser.

Tuttavia, gli attacchi CSRF non sono limitati a sfruttare i cookie. Ad esempio, anche l'autenticazione di base e digest è vulnerabile. Dopo che un utente accede con l'autenticazione di base o digest, il browser invia automaticamente le credenziali fino al termine della sessione.

In questo contesto, la sessione fa riferimento alla sessione sul lato client durante la quale l'utente viene autenticato. Non è correlato alle sessioni lato server o al middleware della sessione ASP.NET Core.

Gli utenti possono proteggersi dalle vulnerabilità CSRF adottando precauzioni:

  • Disconnettersi dalle app Web al termine dell'uso.
  • Cancellare periodicamente i cookie del browser.

Tuttavia, le vulnerabilità CSRF sono fondamentalmente un problema con l'app Web, non con l'utente finale.

Nozioni fondamentali di autenticazione

Cookie-based authentication è una forma comune di autenticazione. I sistemi di autenticazione basati su token sono in continua crescita, in particolare per le applicazioni a pagina singola.

Quando un utente esegue l'autenticazione usando il nome utente e la password, viene rilasciato un token contenente un ticket di autenticazione che può essere usato per l'autenticazione e l'autorizzazione. Il token viene archiviato come oggetto cookie inviato con ogni richiesta eseguita dal client. La generazione e la convalida di questo cookie vengono eseguite dal middleware di autenticazione cookie. Il middleware serializza il principale utente in un cookie crittografato. Nelle richieste successive, il middleware convalida il cookie, ricrea il principale e assegna il principale alla proprietà HttpContext.User.

Autenticazione basata su token

Quando un utente viene autenticato, viene rilasciato un token (non un token antiforgery). Il token contiene informazioni utente sotto forma di attestazioni o di un token di riferimento che indirizza l'app allo stato utente mantenuto all'interno dell'app. Quando un utente tenta di accedere a una risorsa che richiede l'autenticazione, il token viene inviato all'app con un'intestazione di autorizzazione aggiuntiva sotto forma di Bearer token. Questo approccio rende l'applicazione senza stato. In ogni richiesta successiva, il token viene passato nella richiesta di convalida lato server. Questo token non è crittografato, ma viene codificato. Nel server il token viene decodificato per accedere alle informazioni. Per inviare il token alle richieste successive, archiviare il token nella risorsa di archiviazione locale del browser. Posizionare un token nell'archiviazione locale del browser e recuperarlo e usarlo come token di connessione fornisce protezione dagli attacchi CSRF. Tuttavia, se l'app è vulnerabile all'inserimento di script tramite XSS o un file Javascript esterno compromesso, un cyberattacker potrebbe recuperare qualsiasi valore dall'archiviazione locale e inviarlo a se stessi. ASP.NET Core codifica tutti gli output lato server dalle variabili per impostazione predefinita, riducendo il rischio di XSS. Se si esegue l'override di questo comportamento usando Html.Raw o codice personalizzato con input non attendibile, è possibile aumentare il rischio di XSS.

Non preoccuparsi della vulnerabilità CSRF se il token viene archiviato nella risorsa di archiviazione locale del browser. CSRF è un problema quando il token viene memorizzato in un cookie. Per altre informazioni, vedere l'esempio di codice SPA relativo al problema di GitHub che aggiunge due cookie.

Più app ospitate in un dominio

Gli ambienti di hosting condivisi sono vulnerabili all'hijacking della sessione, all'accesso CSRF e ad altri attacchi.

Anche se example1.contoso.net e example2.contoso.net sono host diversi, esiste una relazione di trust implicita tra gli host nel *.contoso.net dominio. Questa relazione di trust implicita consente agli host potenzialmente non attendibili di influire sui cookie degli altri (i criteri di stessa origine che regolano le richieste AJAX non si applicano necessariamente ai cookie HTTP).

Gli attacchi che sfruttano i cookie attendibili tra app ospitate nello stesso dominio possono essere impediti non condividendo domini. Quando ogni app è ospitata nel proprio dominio, non esiste alcuna relazione di trust implicita cookie da sfruttare.

Antifalsificazione in ASP.NET Core

Avviso

ASP.NET Core implementa l'antiforgeria usando ASP.NET Core Data Protection. Lo stack di protezione dati deve essere configurato per funzionare in una server farm. Per altre informazioni, vedere Configurazione della protezione dei dati.

Il middleware antiforgery viene aggiunto al contenitore di Dependency Injection quando viene chiamata una delle API seguenti in Program.cs:

FormTagHelper inserisce token antifalsificazione negli elementi del modulo HTML. Il seguente markup in un file Razor genera automaticamente token anti-contraffazione.

<form method="post">
    <!-- ... -->
</form>

Analogamente, IHtmlHelper.BeginForm genera token antifalsificazione per impostazione predefinita se il metodo del form non è GET.

La generazione automatica di token antiforgery per gli elementi del modulo HTML si verifica quando il <form> tag contiene l'attributo method="post" e uno dei seguenti è true:

  • L'attributo action è vuoto (action="").
  • L'attributo action non viene fornito (<form method="post">).

La generazione automatica di token antiforgery per gli elementi del modulo HTML può essere disabilitata:

  • Disabilitare in modo esplicito i token antifalsificazione con l'attributo asp-antiforgery:

    <form method="post" asp-antiforgery="false">
        <!-- ... -->
    </form>
    
  • L'elemento del modulo è disattivato dagli helper tag usando il simbolo di disattivazione esplicita per gli helper tag:

    <!form method="post">
        <!-- ... -->
    </!form>
    
  • Rimuovere l'oggetto FormTagHelper dalla visualizzazione. L'oggetto FormTagHelper può essere rimosso da una visualizzazione aggiungendo la direttiva seguente alla visualizzazione Razor.

    @removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
    

Nota

Razor Le pagine vengono protette automaticamente da XSRF/CSRF. Per altre informazioni, vedere XSRF/CSRF e Razor Pages.

L'approccio più comune per difendersi dagli attacchi CSRF consiste nell'usare il Synchronizer Token Pattern (STP). STP viene usato quando l'utente richiede una pagina con dati del modulo:

  1. Il server invia un token associato all'identità dell'utente corrente al client.
  2. Il client invia il token al server per la verifica.
  3. Se il server riceve un token che non corrisponde all'identità dell'utente autenticato, la richiesta viene rifiutata.

Il token è univoco e imprevedibile. Il token può essere usato anche per garantire una sequenziazione corretta di una serie di richieste ( ad esempio, verificando la sequenza di richiesta di: pagina 1 > pagina 2 > pagina 3). Tutti i form nei modelli di ASP.NET Core MVC e nelle pagine Razor generano token antiforgery. La coppia di esempi di visualizzazione seguente genera token antiforgery:

<form asp-action="Index" asp-controller="Home" method="post">
    <!-- ... -->
</form>

@using (Html.BeginForm("Index", "Home"))
{
    <!-- ... -->
}

Aggiungere in modo esplicito un token antiforgery a un elemento <form> senza usare Tag Helper con l'helper HTML @Html.AntiForgeryToken.

<form asp-action="Index" asp-controller="Home" method="post">
    @Html.AntiForgeryToken()

    <!-- ... -->
</form>

In ognuno dei casi precedenti, ASP.NET Core aggiunge un campo modulo nascosto simile all'esempio seguente:

<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">

ASP.NET Core include tre filtri per l'uso di token antiforgery:

Anticontraffazione con AddControllers

La chiamata AddControllers non attiva i token antiforgery. AddControllersWithViews deve essere chiamato per ottenere il supporto integrato per i token antiforgery.

Più schede del browser e modello di token del programma di sincronizzazione

Con il modello token del programma di sincronizzazione, solo la pagina caricata più di recente contiene un token antiforgery valido. L'uso di più schede può essere problematico. Ad esempio, se un utente apre più schede:

  • Solo la scheda caricata più di recente contiene un token antiforgery valido.
  • Le richieste effettuate dalle schede caricate in precedenza hanno esito negativo con un errore: Antiforgery token validation failed. The antiforgery cookie token and request token do not match

Valutare modelli di protezione CSRF alternativi se si tratta di un problema.

Configurare l'antifalsificazione con AntiforgeryOptions

Personalizzare AntiforgeryOptions nel file Program dell'app

builder.Services.AddAntiforgery(options =>
{
    // Set Cookie properties using CookieBuilder properties†.
    options.FormFieldName = "AntiforgeryFieldname";
    options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
    options.SuppressXFrameOptionsHeader = false;
});

Impostare le proprietà antiforgery cookie usando le proprietà della classe CookieBuilder, come illustrato nella tabella seguente.

Opzione Descrizione
Cookie Stabilisce le impostazioni utilizzate per creare i cookie antifalsificazione.
FormFieldName Nome del campo modulo nascosto utilizzato dal sistema antiforgery per eseguire il rendering dei token antiforgery nelle visualizzazioni.
HeaderName Il nome dell'intestazione utilizzata dal sistema anti-forgery. Se null, il sistema considera solo i dati del modulo.
SuppressXFrameOptionsHeader Specifica se eliminare la generazione dell'intestazione X-Frame-Options . Per impostazione predefinita, l'intestazione viene generata con il valore "SAMEORIGIN". Il valore predefinito è false.

Alcuni browser non consentono agli endpoint non sicuri di impostare cookie con un flag "sicuro" o sovrascrivere i cookie il cui flag "sicuro" è impostato (per altre informazioni, vedere Deprecate modification of 'secure' cookies from non-secure origin). Poiché la combinazione di endpoint sicuri e non sicuri è uno scenario comune nelle app, ASP.NET Core alleggerisce la restrizione sulla politica di sicurezza per alcuni cookie, come l'antiforgery cookie, impostando il cookie di SecurePolicy su CookieSecurePolicy.None. Anche se un utente malintenzionato ruba un'antiforgeria , deve anche rubare il token antiforgery cookieche viene in genere inviato tramite un campo modulo (più comune) o un'intestazione di richiesta separata (meno comune) più l'autenticazione cookie. I cookie correlati all'autenticazione o all'autorizzazione usano criteri più efficaci rispetto CookieSecurePolicy.Nonea .

Facoltativamente, è possibile proteggere l'antiforgeria cookie in ambienti nonDevelopment usando SSL (Secure Sockets Layer), solo su HTTPS, con l'impostazione della proprietà seguente AntiforgeryOptions.Cookie nel file dell'app Program :

if (!builder.Environment.IsDevelopment())
{
    builder.Services.AddAntiforgery(o =>
    {
        o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    });
}

Per ulteriori informazioni, vedere CookieAuthenticationOptions.

Generare token antiforgery con IAntiforgery

IAntiforgery fornisce l'API per configurare le funzionalità antiforgery. IAntiforgery può essere richiesto in Program.cs tramite WebApplication.Services. L'esempio seguente utilizza un middleware collegato alla pagina iniziale dell'app per generare un token antifrode e inviarlo nella risposta come cookie:

app.UseRouting();

app.UseAuthorization();

var antiforgery = app.Services.GetRequiredService<IAntiforgery>();

app.Use((context, next) =>
{
    var requestPath = context.Request.Path.Value;

    if (string.Equals(requestPath, "/", StringComparison.OrdinalIgnoreCase)
        || string.Equals(requestPath, "/index.html", StringComparison.OrdinalIgnoreCase))
    {
        var tokenSet = antiforgery.GetAndStoreTokens(context);
        context.Response.Cookies.Append("XSRF-TOKEN", tokenSet.RequestToken!,
            new CookieOptions { HttpOnly = false });
    }

    return next(context);
});

Nell'esempio precedente viene impostato un cookie denominato XSRF-TOKEN. Il client può leggere questo cookie e specificarne il valore come intestazione collegata alle richieste AJAX. Ad esempio, Angular include la protezione XSRF integrata che legge un cookie denominato XSRF-TOKEN per impostazione predefinita.

Richiedi convalida antifalsificazione

Il filtro di azione ValidateAntiForgeryToken può essere applicato a una singola azione, a un controller o a livello globale. Le richieste effettuate alle azioni con questo filtro applicato vengono bloccate a meno che la richiesta non includa un token antiforgery valido:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
    // ...

    return RedirectToAction();
}

L'attributo ValidateAntiForgeryToken richiede un token per le richieste ai metodi di azione contrassegnati, incluse le richieste HTTP GET. Se l'attributo ValidateAntiForgeryToken viene applicato attraverso i controller dell'app, può essere sovrascritto con l'attributo IgnoreAntiforgeryToken.

Convalidare automaticamente i token antiforgery solo per metodi HTTP non sicuri

Anziché applicare l'attributo ValidateAntiForgeryToken a livello generale per poi eseguirne l'override con gli attributi IgnoreAntiforgeryToken, è possibile usare l'attributo AutoValidateAntiforgeryToken. Questo attributo funziona in modo identico all'attributo ValidateAntiForgeryToken , ad eccezione del fatto che non richiede token per le richieste effettuate usando i metodi HTTP seguenti:

  • GET
  • HEAD
  • OPZIONI
  • TRACE

È consigliabile l'uso di AutoValidateAntiforgeryToken in modo ampio per scenari non API. Questo attributo garantisce che le azioni POST siano protette per impostazione predefinita. L'alternativa consiste nell'ignorare i token antiforgery per impostazione predefinita, a meno che ValidateAntiForgeryToken venga applicato ai singoli metodi di azione. In questo scenario è più probabile che un metodo di azione POST venga lasciato non protetto per errore, lasciando l'app vulnerabile agli attacchi CSRF. Tutti i POST devono inviare il token antiforgery.

Le API non hanno un meccanismo automatico per l'invio dellacookie parte non del token. L'implementazione dipende probabilmente dall'implementazione del codice client. Di seguito sono riportati alcuni esempi:

Esempio a livello di classe:

[AutoValidateAntiforgeryToken]
public class HomeController : Controller

Esempio globale:

builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});

Sovrascrivere gli attributi antiforgery globali o del controller

Il filtro IgnoreAntiforgeryToken viene usato per eliminare la necessità di un token antiforgery per una determinata azione (o controller). Quando applicato, questo filtro sovrascrive i filtri ValidateAntiForgeryToken e AutoValidateAntiforgeryToken specificati ad un livello superiore (a livello globale o in un controller).

[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
    // ...

    return RedirectToAction();
}

Aggiornare i token dopo l'autenticazione

I token devono essere aggiornati dopo l'autenticazione dell'utente reindirizzando l'utente a una pagina di visualizzazione o Razor pagine.

JavaScript, AJAX e SPA

Nelle app tradizionali basate su HTML, i token antiforgery vengono passati al server tramite campi modulo nascosti. Nelle app moderne basate su JavaScript e nelle applicazioni a pagina singola, molte richieste vengono effettuate programmaticamente. Queste richieste AJAX possono usare altre tecniche (ad esempio intestazioni di richiesta o cookie) per inviare il token.

Se i cookie vengono usati per archiviare i token di autenticazione e per autenticare le richieste API nel server, CSRF è un potenziale problema. Se l'archiviazione locale viene usata per archiviare il token, la vulnerabilità CSRF potrebbe essere mitigata perché i valori dell'archiviazione locale non vengono inviati automaticamente al server con ogni richiesta. L'uso dell'archiviazione locale per archiviare il token antiforgery nel client e inviare il token come intestazione di richiesta è un approccio consigliato.

JavaScript

Usando JavaScript con visualizzazioni, il token può essere creato usando un servizio dall'interno della visualizzazione. Inserire il IAntiforgery servizio nella visualizzazione e chiamare GetAndStoreTokens:

@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery

@{
    ViewData["Title"] = "JavaScript";

    var requestToken = Antiforgery.GetAndStoreTokens(Context).RequestToken;
}

<input id="RequestVerificationToken" type="hidden" value="@requestToken" />

<button id="button" class="btn btn-primary">Submit with Token</button>
<div id="result" class="mt-2"></div>

@section Scripts {
<script>
    document.addEventListener("DOMContentLoaded", () => {
        const resultElement = document.getElementById("result");

        document.getElementById("button").addEventListener("click", async () => {

            const response = await fetch("@Url.Action("FetchEndpoint")", {
                method: "POST",
                headers: {
                    RequestVerificationToken:
                        document.getElementById("RequestVerificationToken").value
                }
            });

            if (response.ok) {
                resultElement.innerText = await response.text();
            } else {
                resultElement.innerText = `Request Failed: ${response.status}`
            }
        });
    });
</script>
}

L'esempio precedente usa JavaScript per leggere il valore del campo nascosto per l'intestazione POST AJAX.

Questo approccio elimina la necessità di gestire direttamente l'impostazione dei cookie dal server o di leggerli dal client. Tuttavia, quando non è possibile inserire il servizio IAntiforgery, utilizzare JavaScript per accedere ai token nei cookie.

  • I token di accesso in una richiesta aggiuntiva al server, di solito in genere same-origin.
  • Utilizzare il contenuto di cookie per creare un'intestazione con il valore del token.

Supponendo che lo script invii il token in un'intestazione di richiesta denominata X-XSRF-TOKEN, configurare il servizio antiforgery per cercare l'intestazione X-XSRF-TOKEN :

builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");

L'esempio seguente aggiunge un endpoint protetto che scrive il token di richiesta in un codice JavaScript leggibile cookie:

app.UseAuthorization();
app.MapGet("antiforgery/token", (IAntiforgery forgeryService, HttpContext context) =>
{
    var tokens = forgeryService.GetAndStoreTokens(context);
    context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken!,
            new CookieOptions { HttpOnly = false });

    return Results.Ok();
}).RequireAuthorization();

L'esempio seguente usa JavaScript per effettuare una richiesta AJAX per ottenere il token e effettuare un'altra richiesta con l'intestazione appropriata:

var response = await fetch("/antiforgery/token", {
    method: "GET",
    headers: { "Authorization": authorizationToken }
});

if (response.ok) {
    // https://developer.mozilla.org/docs/web/api/document/cookie
    const xsrfToken = document.cookie
        .split("; ")
        .find(row => row.startsWith("XSRF-TOKEN="))
        .split("=")[1];

    response = await fetch("/JavaScript/FetchEndpoint", {
        method: "POST",
        headers: { "X-XSRF-TOKEN": xsrfToken, "Authorization": authorizationToken }
    });

    if (response.ok) {
        resultElement.innerText = await response.text();
    } else {
        resultElement.innerText = `Request Failed: ${response.status}`
    }
} else {    
    resultElement.innerText = `Request Failed: ${response.status}`
}

Nota

Quando il token antiforgery viene fornito sia nell'intestazione della richiesta che nel contenuto del modulo, viene convalidato solo il token nell'intestazione.

Antiforgery con API minime

Minimal APIs non supportano l'utilizzo dei filtri inclusi (ValidateAntiForgeryToken, AutoValidateAntiforgeryToken, IgnoreAntiforgeryToken), ma IAntiforgery fornisce le API necessarie per convalidare una richiesta.

Nell'esempio seguente viene creato un filtro che convalida il token antiforgery:

internal static class AntiForgeryExtensions
{
    public static TBuilder ValidateAntiforgery<TBuilder>(this TBuilder builder) where TBuilder : IEndpointConventionBuilder
    {
        return builder.AddEndpointFilter(routeHandlerFilter: async (context, next) =>
        {
            try
            {
                var antiForgeryService = context.HttpContext.RequestServices.GetRequiredService<IAntiforgery>();
                await antiForgeryService.ValidateRequestAsync(context.HttpContext);
            }
            catch (AntiforgeryValidationException)
            {
                return Results.BadRequest("Antiforgery token validation failed.");
            }

            return await next(context);

        });
    }
}

Il filtro può quindi essere applicato a un endpoint:

app.MapPost("api/upload", (IFormFile name) => Results.Accepted())
    .RequireAuthorization()
    .ValidateAntiforgery();

autenticazione Windows e i cookie antifalsificazione

Quando si usa l'autenticazione di Windows, gli endpoint dell'applicazione devono essere protetti dagli attacchi CSRF nello stesso modo usato per i cookie. Il browser invia in modo implicito il contesto di autenticazione al server e agli endpoint devono essere protetti dagli attacchi CSRF.

Estendere il sistema anti-contraffazione

Il tipo IAntiforgeryAdditionalDataProvider permette agli sviluppatori di espandere il comportamento del sistema anti-CSRF trasferendo dati aggiuntivi in ogni token. Il GetAdditionalData metodo viene chiamato ogni volta che viene generato un token di campo e il valore restituito viene incorporato all'interno del token generato. Un implementatore può restituire un timestamp, un nonce o qualsiasi altro valore e quindi chiamare ValidateAdditionalData per convalidare questi dati quando il token viene convalidato. Il nome utente del client è già incorporato nei token generati, quindi non è necessario includere queste informazioni. Se un token include dati supplementari ma non IAntiForgeryAdditionalDataProvider è configurato, i dati supplementari non vengono convalidati.

Risorse aggiuntive

La falsificazione di richiesta intersito (nota anche come XSRF o CSRF) è un attacco contro le applicazioni ospitate sul Web in cui un'applicazione Web dannosa può influenzare l'interazione tra il browser del client e un'applicazione Web che considera attendibile quel browser. Questi attacchi sono possibili perché i Web browser inviano automaticamente alcuni tipi di token di autenticazione con ogni richiesta a un sito Web. Questa forma di exploit è nota anche come attacco con un clic o guida di sessione perché l'attacco sfrutta la sessione autenticata in precedenza dell'utente.

Un esempio di attacco CSRF:

  1. Un utente accede a www.good-banking-site.example.com utilizzando l'autenticazione basata su form. Il server autentica l'utente e rilascia una risposta che include un'autenticazione cookie. Il sito è vulnerabile all'attacco perché considera attendibile qualsiasi richiesta ricevuta con un'autenticazione cookievalida.

  2. L'utente visita un sito dannoso, www.bad-crook-site.example.com.

    Il sito dannoso, www.bad-crook-site.example.com, contiene un modulo HTML simile all'esempio seguente:

    <h1>Congratulations! You're a Winner!</h1>
    <form action="https://www.good-banking-site.example.com/api/account" method="post">
        <input type="hidden" name="Transaction" value="withdraw" />
        <input type="hidden" name="Amount" value="1000000" />
        <input type="submit" value="Click to collect your prize!" />
    </form>
    

    Si noti che il modulo action invia i dati al sito vulnerabile, non al sito dannoso. Questa è la parte "cross-site" di CSRF.

  3. L'utente seleziona il pulsante invia. Il browser effettua la richiesta e include automaticamente l'autenticazione cookie per il dominio richiesto, www.good-banking-site.example.com.

  4. La richiesta viene eseguita sul www.good-banking-site.example.com server con il contesto di autenticazione dell'utente e può eseguire qualsiasi azione che un utente autenticato possa eseguire.

Oltre allo scenario in cui l'utente seleziona il pulsante per inviare il modulo, il sito dannoso potrebbe:

  • Eseguire uno script che invia automaticamente il modulo.
  • Inviare il modulo come richiesta AJAX.
  • Nascondere il modulo usando CSS.

Questi scenari alternativi non richiedono alcuna azione o input da parte dell'utente diverso da visitare inizialmente il sito dannoso.

L'uso di HTTPS non impedisce un attacco CSRF. Il sito dannoso può inviare una richiesta https://www.good-banking-site.example.com/ con la stessa facilità con cui può inviare una richiesta non sicura.

Alcuni attacchi usano endpoint che rispondono alle richieste GET, nel qual caso è possibile usare un tag immagine per eseguire l'azione. Questa forma di attacco è comune nei siti del forum che consentono immagini ma bloccano JavaScript. Le app che cambiano lo stato nelle richieste GET, in cui le variabili o le risorse vengono modificate, sono vulnerabili ad attacchi dannosi. Le richieste GET che cambiano lo stato non sono sicure. Una procedura consigliata consiste nel non modificare mai lo stato in una richiesta GET.

Gli attacchi CSRF sono possibili contro le app Web che usano cookie per l'autenticazione perché:

  • I browser archivia i cookie rilasciati da un'app Web.
  • I cookie archiviati includono cookie di sessione per gli utenti autenticati.
  • I browser inviano tutti i cookie associati a un dominio all'app Web ogni richiesta indipendentemente dalla modalità di generazione della richiesta all'app all'interno del browser.

Tuttavia, gli attacchi CSRF non sono limitati a sfruttare i cookie. Ad esempio, anche l'autenticazione di base e digest è vulnerabile. Dopo che un utente accede con l'autenticazione di base o digest, il browser invia automaticamente le credenziali fino al termine della sessione.

In questo contesto, la sessione fa riferimento alla sessione sul lato client durante la quale l'utente viene autenticato. Non è correlato alle sessioni lato server o al middleware della sessione ASP.NET Core.

Gli utenti possono proteggersi dalle vulnerabilità CSRF adottando precauzioni:

  • Disconnettersi dalle app Web al termine dell'uso.
  • Cancellare periodicamente i cookie del browser.

Tuttavia, le vulnerabilità CSRF sono fondamentalmente un problema con l'app Web, non con l'utente finale.

Nozioni fondamentali di autenticazione

Cookie-based authentication è una forma comune di autenticazione. I sistemi di autenticazione basati su token sono in continua crescita, in particolare per le applicazioni a pagina singola.

Quando un utente esegue l'autenticazione usando il nome utente e la password, viene rilasciato un token contenente un ticket di autenticazione che può essere usato per l'autenticazione e l'autorizzazione. Il token viene archiviato come oggetto cookie inviato con ogni richiesta eseguita dal client. La generazione e la convalida di questo cookie vengono eseguite dal middleware di autenticazione cookie. Il middleware serializza il principale utente in un cookie crittografato. Nelle richieste successive, il middleware convalida il cookie, ricrea il principale e assegna il principale alla proprietà HttpContext.User.

Autenticazione basata su token

Quando un utente viene autenticato, viene rilasciato un token (non un token antiforgery). Il token contiene informazioni utente sotto forma di attestazioni o di un token di riferimento che indirizza l'app allo stato utente mantenuto all'interno dell'app. Quando un utente tenta di accedere a una risorsa che richiede l'autenticazione, il token viene inviato all'app con un'intestazione di autorizzazione aggiuntiva sotto forma di Bearer token. Questo approccio rende l'applicazione senza stato. In ogni richiesta successiva, il token viene passato nella richiesta di convalida lato server. Questo token non è crittografato, ma viene codificato. Nel server il token viene decodificato per accedere alle informazioni. Per inviare il token alle richieste successive, archiviare il token nella risorsa di archiviazione locale del browser. Non preoccuparsi della vulnerabilità CSRF se il token viene archiviato nella risorsa di archiviazione locale del browser. CSRF è un problema quando il token viene memorizzato in un cookie. Per altre informazioni, vedere l'esempio di codice SPA relativo al problema di GitHub che aggiunge due cookie.

Più app ospitate in un dominio

Gli ambienti di hosting condivisi sono vulnerabili all'hijacking della sessione, all'accesso CSRF e ad altri attacchi.

Anche se example1.contoso.net e example2.contoso.net sono host diversi, esiste una relazione di trust implicita tra gli host nel *.contoso.net dominio. Questa relazione di trust implicita consente agli host potenzialmente non attendibili di influire sui cookie degli altri (i criteri di stessa origine che regolano le richieste AJAX non si applicano necessariamente ai cookie HTTP).

Gli attacchi che sfruttano i cookie attendibili tra app ospitate nello stesso dominio possono essere impediti non condividendo domini. Quando ogni app è ospitata nel proprio dominio, non esiste alcuna relazione di trust implicita cookie da sfruttare.

Antifalsificazione in ASP.NET Core

Avviso

ASP.NET Core implementa l'antiforgeria usando ASP.NET Core Data Protection. Lo stack di protezione dati deve essere configurato per funzionare in una server farm. Per altre informazioni, vedere Configurazione della protezione dei dati.

Il middleware antiforgery viene aggiunto al contenitore di Dependency Injection quando viene chiamata una delle API seguenti in Program.cs:

FormTagHelper inserisce token antifalsificazione negli elementi del modulo HTML. Il seguente markup in un file Razor genera automaticamente token anti-contraffazione.

<form method="post">
    <!-- ... -->
</form>

Analogamente, IHtmlHelper.BeginForm genera token antifalsificazione per impostazione predefinita se il metodo del form non è GET.

La generazione automatica di token antiforgery per gli elementi del modulo HTML si verifica quando il <form> tag contiene l'attributo method="post" e uno dei seguenti è true:

  • L'attributo action è vuoto (action="").
  • L'attributo action non viene fornito (<form method="post">).

La generazione automatica di token antiforgery per gli elementi del modulo HTML può essere disabilitata:

  • Disabilitare in modo esplicito i token antifalsificazione con l'attributo asp-antiforgery:

    <form method="post" asp-antiforgery="false">
        <!-- ... -->
    </form>
    
  • L'elemento del modulo è disattivato dagli helper tag usando il simbolo di disattivazione esplicita per gli helper tag:

    <!form method="post">
        <!-- ... -->
    </!form>
    
  • Rimuovere l'oggetto FormTagHelper dalla visualizzazione. L'oggetto FormTagHelper può essere rimosso da una visualizzazione aggiungendo la direttiva seguente alla visualizzazione Razor.

    @removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
    

Nota

Razor Le pagine vengono protette automaticamente da XSRF/CSRF. Per altre informazioni, vedere XSRF/CSRF e Razor Pages.

L'approccio più comune per difendersi dagli attacchi CSRF consiste nell'usare il Synchronizer Token Pattern (STP). STP viene usato quando l'utente richiede una pagina con dati del modulo:

  1. Il server invia un token associato all'identità dell'utente corrente al client.
  2. Il client invia il token al server per la verifica.
  3. Se il server riceve un token che non corrisponde all'identità dell'utente autenticato, la richiesta viene rifiutata.

Il token è univoco e imprevedibile. Il token può essere usato anche per garantire una sequenziazione corretta di una serie di richieste ( ad esempio, verificando la sequenza di richiesta di: pagina 1 > pagina 2 > pagina 3). Tutti i form nei modelli di ASP.NET Core MVC e nelle pagine Razor generano token antiforgery. La coppia di esempi di visualizzazione seguente genera token antiforgery:

<form asp-action="Index" asp-controller="Home" method="post">
    <!-- ... -->
</form>

@using (Html.BeginForm("Index", "Home"))
{
    <!-- ... -->
}

Aggiungere in modo esplicito un token antiforgery a un elemento <form> senza usare Tag Helper con l'helper HTML @Html.AntiForgeryToken.

<form asp-action="Index" asp-controller="Home" method="post">
    @Html.AntiForgeryToken()

    <!-- ... -->
</form>

In ognuno dei casi precedenti, ASP.NET Core aggiunge un campo modulo nascosto simile all'esempio seguente:

<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">

ASP.NET Core include tre filtri per l'uso di token antiforgery:

Anticontraffazione con AddControllers

La chiamata AddControllers non attiva i token antiforgery. AddControllersWithViews deve essere chiamato per ottenere il supporto integrato per i token antiforgery.

Più schede del browser e modello di token del programma di sincronizzazione

Con il modello token del programma di sincronizzazione, solo la pagina caricata più di recente contiene un token antiforgery valido. L'uso di più schede può essere problematico. Ad esempio, se un utente apre più schede:

  • Solo la scheda caricata più di recente contiene un token antiforgery valido.
  • Le richieste effettuate dalle schede caricate in precedenza hanno esito negativo con un errore: Antiforgery token validation failed. The antiforgery cookie token and request token do not match

Valutare modelli di protezione CSRF alternativi se si tratta di un problema.

Configurare l'antifalsificazione con AntiforgeryOptions

Personalizzare AntiforgeryOptions nel file Program dell'app

builder.Services.AddAntiforgery(options =>
{
    // Set Cookie properties using CookieBuilder properties†.
    options.FormFieldName = "AntiforgeryFieldname";
    options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
    options.SuppressXFrameOptionsHeader = false;
});

Impostare le proprietà antiforgery cookie usando le proprietà della classe CookieBuilder, come illustrato nella tabella seguente.

Opzione Descrizione
Cookie Stabilisce le impostazioni utilizzate per creare i cookie antifalsificazione.
FormFieldName Nome del campo modulo nascosto utilizzato dal sistema antiforgery per eseguire il rendering dei token antiforgery nelle visualizzazioni.
HeaderName Il nome dell'intestazione utilizzata dal sistema anti-forgery. Se null, il sistema considera solo i dati del modulo.
SuppressXFrameOptionsHeader Specifica se eliminare la generazione dell'intestazione X-Frame-Options . Per impostazione predefinita, l'intestazione viene generata con il valore "SAMEORIGIN". Il valore predefinito è false.

Alcuni browser non consentono agli endpoint non sicuri di impostare cookie con un flag "sicuro" o sovrascrivere i cookie il cui flag "sicuro" è impostato (per altre informazioni, vedere Deprecate modification of 'secure' cookies from non-secure origin). Poiché la combinazione di endpoint sicuri e non sicuri è uno scenario comune nelle app, ASP.NET Core alleggerisce la restrizione sulla politica di sicurezza per alcuni cookie, come l'antiforgery cookie, impostando il cookie di SecurePolicy su CookieSecurePolicy.None. Anche se un utente malintenzionato ruba un'antiforgeria , deve anche rubare il token antiforgery cookieche viene in genere inviato tramite un campo modulo (più comune) o un'intestazione di richiesta separata (meno comune) più l'autenticazione cookie. I cookie correlati all'autenticazione o all'autorizzazione usano criteri più efficaci rispetto CookieSecurePolicy.Nonea .

Facoltativamente, è possibile proteggere l'antiforgeria cookie in ambienti nonDevelopment usando SSL (Secure Sockets Layer), solo su HTTPS, con l'impostazione della proprietà seguente AntiforgeryOptions.Cookie nel file dell'app Program :

if (!builder.Environment.IsDevelopment())
{
    builder.Services.AddAntiforgery(o =>
    {
        o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    });
}

Per ulteriori informazioni, vedere CookieAuthenticationOptions.

Generare token antiforgery con IAntiforgery

IAntiforgery fornisce l'API per configurare le funzionalità antiforgery. IAntiforgery può essere richiesto in Program.cs tramite WebApplication.Services. L'esempio seguente utilizza un middleware collegato alla pagina iniziale dell'app per generare un token antifrode e inviarlo nella risposta come cookie:

app.UseRouting();

app.UseAuthorization();

var antiforgery = app.Services.GetRequiredService<IAntiforgery>();

app.Use((context, next) =>
{
    var requestPath = context.Request.Path.Value;

    if (string.Equals(requestPath, "/", StringComparison.OrdinalIgnoreCase)
        || string.Equals(requestPath, "/index.html", StringComparison.OrdinalIgnoreCase))
    {
        var tokenSet = antiforgery.GetAndStoreTokens(context);
        context.Response.Cookies.Append("XSRF-TOKEN", tokenSet.RequestToken!,
            new CookieOptions { HttpOnly = false });
    }

    return next(context);
});

Nell'esempio precedente viene impostato un cookie denominato XSRF-TOKEN. Il client può leggere questo cookie e specificarne il valore come intestazione collegata alle richieste AJAX. Ad esempio, Angular include la protezione XSRF integrata che legge un cookie denominato XSRF-TOKEN per impostazione predefinita.

Richiedi convalida antifalsificazione

Il filtro di azione ValidateAntiForgeryToken può essere applicato a una singola azione, a un controller o a livello globale. Le richieste effettuate alle azioni con questo filtro applicato vengono bloccate a meno che la richiesta non includa un token antiforgery valido:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
    // ...

    return RedirectToAction();
}

L'attributo ValidateAntiForgeryToken richiede un token per le richieste ai metodi di azione contrassegnati, incluse le richieste HTTP GET. Se l'attributo ValidateAntiForgeryToken viene applicato attraverso i controller dell'app, può essere sovrascritto con l'attributo IgnoreAntiforgeryToken.

Convalidare automaticamente i token antiforgery solo per metodi HTTP non sicuri

Anziché applicare l'attributo ValidateAntiForgeryToken a livello generale per poi eseguirne l'override con gli attributi IgnoreAntiforgeryToken, è possibile usare l'attributo AutoValidateAntiforgeryToken. Questo attributo funziona in modo identico all'attributo ValidateAntiForgeryToken , ad eccezione del fatto che non richiede token per le richieste effettuate usando i metodi HTTP seguenti:

  • GET
  • HEAD
  • OPZIONI
  • TRACE

È consigliabile l'uso di AutoValidateAntiforgeryToken in modo ampio per scenari non API. Questo attributo garantisce che le azioni POST siano protette per impostazione predefinita. L'alternativa consiste nell'ignorare i token antiforgery per impostazione predefinita, a meno che ValidateAntiForgeryToken venga applicato ai singoli metodi di azione. In questo scenario è più probabile che un metodo di azione POST venga lasciato non protetto per errore, lasciando l'app vulnerabile agli attacchi CSRF. Tutti i POST devono inviare il token antiforgery.

Le API non hanno un meccanismo automatico per l'invio dellacookie parte non del token. L'implementazione dipende probabilmente dall'implementazione del codice client. Di seguito sono riportati alcuni esempi:

Esempio a livello di classe:

[AutoValidateAntiforgeryToken]
public class HomeController : Controller

Esempio globale:

builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});

Sovrascrivere gli attributi antiforgery globali o del controller

Il filtro IgnoreAntiforgeryToken viene usato per eliminare la necessità di un token antiforgery per una determinata azione (o controller). Quando applicato, questo filtro sovrascrive i filtri ValidateAntiForgeryToken e AutoValidateAntiforgeryToken specificati ad un livello superiore (a livello globale o in un controller).

[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
    // ...

    return RedirectToAction();
}

Aggiornare i token dopo l'autenticazione

I token devono essere aggiornati dopo l'autenticazione dell'utente reindirizzando l'utente a una pagina di visualizzazione o Razor pagine.

JavaScript, AJAX e SPA

Nelle app tradizionali basate su HTML, i token antiforgery vengono passati al server tramite campi modulo nascosti. Nelle app moderne basate su JavaScript e nelle applicazioni a pagina singola, molte richieste vengono effettuate programmaticamente. Queste richieste AJAX possono usare altre tecniche (ad esempio intestazioni di richiesta o cookie) per inviare il token.

Se i cookie vengono usati per archiviare i token di autenticazione e per autenticare le richieste API nel server, CSRF è un potenziale problema. Se l'archiviazione locale viene usata per archiviare il token, la vulnerabilità CSRF potrebbe essere mitigata perché i valori dell'archiviazione locale non vengono inviati automaticamente al server con ogni richiesta. L'uso dell'archiviazione locale per archiviare il token antiforgery nel client e inviare il token come intestazione di richiesta è un approccio consigliato.

JavaScript

Usando JavaScript con visualizzazioni, il token può essere creato usando un servizio dall'interno della visualizzazione. Inserire il IAntiforgery servizio nella visualizzazione e chiamare GetAndStoreTokens:

@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery

@{
    ViewData["Title"] = "JavaScript";

    var requestToken = Antiforgery.GetAndStoreTokens(Context).RequestToken;
}

<input id="RequestVerificationToken" type="hidden" value="@requestToken" />

<button id="button" class="btn btn-primary">Submit with Token</button>
<div id="result" class="mt-2"></div>

@section Scripts {
<script>
    document.addEventListener("DOMContentLoaded", () => {
        const resultElement = document.getElementById("result");

        document.getElementById("button").addEventListener("click", async () => {

            const response = await fetch("@Url.Action("FetchEndpoint")", {
                method: "POST",
                headers: {
                    RequestVerificationToken:
                        document.getElementById("RequestVerificationToken").value
                }
            });

            if (response.ok) {
                resultElement.innerText = await response.text();
            } else {
                resultElement.innerText = `Request Failed: ${response.status}`
            }
        });
    });
</script>
}

L'esempio precedente usa JavaScript per leggere il valore del campo nascosto per l'intestazione POST AJAX.

Questo approccio elimina la necessità di gestire direttamente l'impostazione dei cookie dal server o di leggerli dal client. Tuttavia, quando non è possibile iniettare il servizio IAntiforgery, JavaScript può anche accedere al token nei cookie, che è ottenuto da una richiesta aggiuntiva al server (in genere same-origin), e usare il contenuto di cookie per creare un'intestazione con il valore del token.

Supponendo che lo script invii il token in un'intestazione di richiesta denominata X-XSRF-TOKEN, configurare il servizio antiforgery per cercare l'intestazione X-XSRF-TOKEN :

builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");

L'esempio seguente aggiunge un endpoint protetto che scriverà il token di richiesta in un codice JavaScript leggibile cookie:

app.UseAuthorization();
app.MapGet("antiforgery/token", (IAntiforgery forgeryService, HttpContext context) =>
{
    var tokens = forgeryService.GetAndStoreTokens(context);
    context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken!,
            new CookieOptions { HttpOnly = false });

    return Results.Ok();
}).RequireAuthorization();

L'esempio seguente usa JavaScript per effettuare una richiesta AJAX per ottenere il token e effettuare un'altra richiesta con l'intestazione appropriata:

var response = await fetch("/antiforgery/token", {
    method: "GET",
    headers: { "Authorization": authorizationToken }
});

if (response.ok) {
    // https://developer.mozilla.org/docs/web/api/document/cookie
    const xsrfToken = document.cookie
        .split("; ")
        .find(row => row.startsWith("XSRF-TOKEN="))
        .split("=")[1];

    response = await fetch("/JavaScript/FetchEndpoint", {
        method: "POST",
        headers: { "X-XSRF-TOKEN": xsrfToken, "Authorization": authorizationToken }
    });

    if (response.ok) {
        resultElement.innerText = await response.text();
    } else {
        resultElement.innerText = `Request Failed: ${response.status}`
    }
} else {    
    resultElement.innerText = `Request Failed: ${response.status}`
}

autenticazione Windows e i cookie antifalsificazione

Quando si usa l'autenticazione di Windows, gli endpoint dell'applicazione devono essere protetti dagli attacchi CSRF nello stesso modo usato per i cookie. Il browser invia in modo implicito il contesto di autenticazione al server e quindi gli endpoint devono essere protetti dagli attacchi CSRF.

Estendere il sistema anti-contraffazione

Il tipo IAntiforgeryAdditionalDataProvider permette agli sviluppatori di espandere il comportamento del sistema anti-CSRF trasferendo dati aggiuntivi in ogni token. Il GetAdditionalData metodo viene chiamato ogni volta che viene generato un token di campo e il valore restituito viene incorporato all'interno del token generato. Un implementatore può restituire un timestamp, un nonce o qualsiasi altro valore e quindi chiamare ValidateAdditionalData per convalidare questi dati quando il token viene convalidato. Il nome utente del client è già incorporato nei token generati, quindi non è necessario includere queste informazioni. Se un token include dati supplementari ma non IAntiForgeryAdditionalDataProvider è configurato, i dati supplementari non vengono convalidati.

Risorse aggiuntive

La falsificazione di richiesta intersito (nota anche come XSRF o CSRF) è un attacco contro le applicazioni ospitate sul Web in cui un'applicazione Web dannosa può influenzare l'interazione tra il browser del client e un'applicazione Web che considera attendibile quel browser. Questi attacchi sono possibili perché i Web browser inviano automaticamente alcuni tipi di token di autenticazione con ogni richiesta a un sito Web. Questa forma di exploit è nota anche come attacco con un clic o guida di sessione perché l'attacco sfrutta la sessione autenticata in precedenza dell'utente.

Un esempio di attacco CSRF:

  1. Un utente accede a www.good-banking-site.example.com utilizzando l'autenticazione basata su form. Il server autentica l'utente e rilascia una risposta che include un'autenticazione cookie. Il sito è vulnerabile all'attacco perché considera attendibile qualsiasi richiesta ricevuta con un'autenticazione cookievalida.

  2. L'utente visita un sito dannoso, www.bad-crook-site.example.com.

    Il sito dannoso, www.bad-crook-site.example.com, contiene un modulo HTML simile all'esempio seguente:

    <h1>Congratulations! You're a Winner!</h1>
    <form action="https://www.good-banking-site.example.com/api/account" method="post">
        <input type="hidden" name="Transaction" value="withdraw" />
        <input type="hidden" name="Amount" value="1000000" />
        <input type="submit" value="Click to collect your prize!" />
    </form>
    

    Si noti che il modulo action invia i dati al sito vulnerabile, non al sito dannoso. Questa è la parte "cross-site" di CSRF.

  3. L'utente seleziona il pulsante invia. Il browser effettua la richiesta e include automaticamente l'autenticazione cookie per il dominio richiesto, www.good-banking-site.example.com.

  4. La richiesta viene eseguita sul www.good-banking-site.example.com server con il contesto di autenticazione dell'utente e può eseguire qualsiasi azione che un utente autenticato possa eseguire.

Oltre allo scenario in cui l'utente seleziona il pulsante per inviare il modulo, il sito dannoso potrebbe:

  • Eseguire uno script che invia automaticamente il modulo.
  • Inviare il modulo come richiesta AJAX.
  • Nascondere il modulo usando CSS.

Questi scenari alternativi non richiedono alcuna azione o input da parte dell'utente diverso da visitare inizialmente il sito dannoso.

L'uso di HTTPS non impedisce un attacco CSRF. Il sito dannoso può inviare una richiesta https://www.good-banking-site.example.com/ con la stessa facilità con cui può inviare una richiesta non sicura.

Alcuni attacchi usano endpoint che rispondono alle richieste GET, nel qual caso è possibile usare un tag immagine per eseguire l'azione. Questa forma di attacco è comune nei siti del forum che consentono immagini ma bloccano JavaScript. Le app che cambiano lo stato nelle richieste GET, in cui le variabili o le risorse vengono modificate, sono vulnerabili ad attacchi dannosi. Le richieste GET che cambiano lo stato non sono sicure. Una procedura consigliata consiste nel non modificare mai lo stato in una richiesta GET.

Gli attacchi CSRF sono possibili contro le app Web che usano cookie per l'autenticazione perché:

  • I browser archivia i cookie rilasciati da un'app Web.
  • I cookie archiviati includono cookie di sessione per gli utenti autenticati.
  • I browser inviano tutti i cookie associati a un dominio all'app Web ogni richiesta indipendentemente dalla modalità di generazione della richiesta all'app all'interno del browser.

Tuttavia, gli attacchi CSRF non sono limitati a sfruttare i cookie. Ad esempio, anche l'autenticazione di base e digest è vulnerabile. Dopo che un utente accede con l'autenticazione di base o digest, il browser invia automaticamente le credenziali fino al termine della sessione.

In questo contesto, la sessione fa riferimento alla sessione sul lato client durante la quale l'utente viene autenticato. Non è correlato alle sessioni lato server o al middleware della sessione ASP.NET Core.

Gli utenti possono proteggersi dalle vulnerabilità CSRF adottando precauzioni:

  • Disconnettersi dalle app Web al termine dell'uso.
  • Cancellare periodicamente i cookie del browser.

Tuttavia, le vulnerabilità CSRF sono fondamentalmente un problema con l'app Web, non con l'utente finale.

Nozioni fondamentali di autenticazione

Cookie-based authentication è una forma comune di autenticazione. I sistemi di autenticazione basati su token sono in continua crescita, in particolare per le applicazioni a pagina singola.

Quando un utente esegue l'autenticazione usando il nome utente e la password, viene rilasciato un token contenente un ticket di autenticazione che può essere usato per l'autenticazione e l'autorizzazione. Il token viene archiviato come oggetto cookie inviato con ogni richiesta eseguita dal client. La generazione e la convalida di questo cookie vengono eseguite dal middleware di autenticazione cookie. Il middleware serializza il principale utente in un cookie crittografato. Nelle richieste successive, il middleware convalida il cookie, ricrea il principale e assegna il principale alla proprietà HttpContext.User.

Autenticazione basata su token

Quando un utente viene autenticato, viene rilasciato un token (non un token antiforgery). Il token contiene informazioni utente sotto forma di attestazioni o di un token di riferimento che indirizza l'app allo stato utente mantenuto all'interno dell'app. Quando un utente tenta di accedere a una risorsa che richiede l'autenticazione, il token viene inviato all'app con un'intestazione di autorizzazione aggiuntiva sotto forma di Bearer token. Questo approccio rende l'applicazione senza stato. In ogni richiesta successiva, il token viene passato nella richiesta di convalida lato server. Questo token non è crittografato, ma viene codificato. Nel server il token viene decodificato per accedere alle informazioni. Per inviare il token alle richieste successive, archiviare il token nella risorsa di archiviazione locale del browser. Non preoccuparsi della vulnerabilità CSRF se il token viene archiviato nella risorsa di archiviazione locale del browser. CSRF è un problema quando il token viene memorizzato in un cookie. Per altre informazioni, vedere l'esempio di codice SPA relativo al problema di GitHub che aggiunge due cookie.

Più app ospitate in un dominio

Gli ambienti di hosting condivisi sono vulnerabili all'hijacking della sessione, all'accesso CSRF e ad altri attacchi.

Anche se example1.contoso.net e example2.contoso.net sono host diversi, esiste una relazione di trust implicita tra gli host nel *.contoso.net dominio. Questa relazione di trust implicita consente agli host potenzialmente non attendibili di influire sui cookie degli altri (i criteri di stessa origine che regolano le richieste AJAX non si applicano necessariamente ai cookie HTTP).

Gli attacchi che sfruttano i cookie attendibili tra app ospitate nello stesso dominio possono essere impediti non condividendo domini. Quando ogni app è ospitata nel proprio dominio, non esiste alcuna relazione di trust implicita cookie da sfruttare.

configurazione anti-contraffazione di ASP.NET Core

Avviso

ASP.NET Core implementa l'antiforgeria usando ASP.NET Core Data Protection. Lo stack di protezione dati deve essere configurato per funzionare in una server farm. Per altre informazioni, vedere Configurazione della protezione dei dati.

Il middleware antiforgery viene aggiunto al contenitore di Dependency Injection quando viene chiamata una delle API seguenti in Startup.ConfigureServices:

In ASP.NET Core 2.0 o versione successiva, FormTagHelper inserisce i token antiforgery negli elementi del modulo HTML. Il seguente markup in un file Razor genera automaticamente token anti-contraffazione.

<form method="post">
    ...
</form>

Analogamente, IHtmlHelper.BeginForm genera token antifalsificazione per impostazione predefinita se il metodo del form non è GET.

La generazione automatica di token antiforgery per gli elementi del modulo HTML si verifica quando il <form> tag contiene l'attributo method="post" e uno dei seguenti è true:

  • L'attributo action è vuoto (action="").
  • L'attributo action non viene fornito (<form method="post">).

La generazione automatica di token antiforgery per gli elementi del modulo HTML può essere disabilitata:

  • Disabilitare in modo esplicito i token antifalsificazione con l'attributo asp-antiforgery:

    <form method="post" asp-antiforgery="false">
        ...
    </form>
    
  • L'elemento del modulo è disattivato dagli helper tag usando il simbolo di disattivazione esplicita per gli helper tag:

    <!form method="post">
        ...
    </!form>
    
  • Rimuovere l'oggetto FormTagHelper dalla visualizzazione. L'oggetto FormTagHelper può essere rimosso da una visualizzazione aggiungendo la direttiva seguente alla visualizzazione Razor.

    @removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
    

Nota

Razor Le pagine vengono protette automaticamente da XSRF/CSRF. Per altre informazioni, vedere XSRF/CSRF e Razor Pages.

L'approccio più comune per difendersi dagli attacchi CSRF consiste nell'usare il Synchronizer Token Pattern (STP). STP viene usato quando l'utente richiede una pagina con dati del modulo:

  1. Il server invia un token associato all'identità dell'utente corrente al client.
  2. Il client invia il token al server per la verifica.
  3. Se il server riceve un token che non corrisponde all'identità dell'utente autenticato, la richiesta viene rifiutata.

Il token è univoco e imprevedibile. Il token può essere usato anche per garantire una sequenziazione corretta di una serie di richieste ( ad esempio, verificando la sequenza di richiesta di: pagina 1 > pagina 2 > pagina 3). Tutti i form nei modelli di ASP.NET Core MVC e nelle pagine Razor generano token antiforgery. La coppia di esempi di visualizzazione seguente genera token antiforgery:

<form asp-controller="Todo" asp-action="Create" method="post">
    ...
</form>

@using (Html.BeginForm("Create", "Todo"))
{
    ...
}

Aggiungere in modo esplicito un token antiforgery a un elemento <form> senza usare Tag Helper con l'helper HTML @Html.AntiForgeryToken.

<form action="/" method="post">
    @Html.AntiForgeryToken()
</form>

In ognuno dei casi precedenti, ASP.NET Core aggiunge un campo modulo nascosto simile all'esempio seguente:

<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">

ASP.NET Core include tre filtri per l'uso di token antiforgery:

Opzioni antiforgery

Personalizzare AntiforgeryOptions in Startup.ConfigureServices:

services.AddAntiforgery(options => 
{
    options.FormFieldName = "AntiforgeryFieldname";
    options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
    options.SuppressXFrameOptionsHeader = false;
});

Impostare le proprietà antiforgery cookie usando le proprietà della classe CookieBuilder, come illustrato nella tabella seguente.

Opzione Descrizione
Cookie Stabilisce le impostazioni utilizzate per creare i cookie antifalsificazione.
FormFieldName Nome del campo modulo nascosto utilizzato dal sistema antiforgery per eseguire il rendering dei token antiforgery nelle visualizzazioni.
HeaderName Il nome dell'intestazione utilizzata dal sistema anti-forgery. Se null, il sistema considera solo i dati del modulo.
SuppressXFrameOptionsHeader Specifica se eliminare la generazione dell'intestazione X-Frame-Options . Per impostazione predefinita, l'intestazione viene generata con il valore "SAMEORIGIN". Il valore predefinito è false.

Alcuni browser non consentono agli endpoint non sicuri di impostare cookie con un flag "sicuro" o sovrascrivere i cookie il cui flag "sicuro" è impostato (per altre informazioni, vedere Deprecate modification of 'secure' cookies from non-secure origin). Poiché la combinazione di endpoint sicuri e non sicuri è uno scenario comune nelle app, ASP.NET Core alleggerisce la restrizione sulla politica di sicurezza per alcuni cookie, come l'antiforgery cookie, impostando il cookie di SecurePolicy su CookieSecurePolicy.None. Anche se un utente malintenzionato ruba un'antiforgeria , deve anche rubare il token antiforgery cookieche viene in genere inviato tramite un campo modulo (più comune) o un'intestazione di richiesta separata (meno comune) più l'autenticazione cookie. I cookie correlati all'autenticazione o all'autorizzazione usano criteri più efficaci rispetto CookieSecurePolicy.Nonea .

Facoltativamente, è possibile proteggere l'antiforgeria cookie in ambienti nonDevelopment usando SSL (Secure Sockets Layer), solo su HTTPS, con l'impostazione della proprietà seguente AntiforgeryOptions.Cookie nella classe dell'app Startup :

public class Startup
{
    public Startup(IConfiguration configuration, IHostEnvironment environment)
    {
        Configuration = configuration;
        Environment = environment;
    }

    public IConfiguration Configuration { get; }
    public IHostEnvironment Environment { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        // Other services are registered here

        if (!Environment.IsDevelopment())
        {
            services.AddAntiforgery(o =>
            {
                o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
            });
        }
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // Request processing pipeline
    }
}

Per ulteriori informazioni, vedere CookieAuthenticationOptions.

Configurare le funzionalità di antifalsificazione con IAntiforgery

IAntiforgery fornisce l'API per configurare le funzionalità antiforgery. IAntiforgery può essere richiesto nel Configure metodo della Startup classe .

Nell'esempio seguente :

  • Il middleware dalla pagina iniziale dell'app viene usato per generare un token antiforgery e inviarlo nella risposta come cookie.
  • Il token di richiesta viene inviato come javaScript leggibile con la convenzione di denominazione cookie angular predefinita descritta nella sezione AngularJS .
public void Configure(IApplicationBuilder app, IAntiforgery antiforgery)
{
    app.Use(next => context =>
    {
        string path = context.Request.Path.Value;

        if (string.Equals(path, "/", StringComparison.OrdinalIgnoreCase) ||
            string.Equals(path, "/index.html", StringComparison.OrdinalIgnoreCase))
        {
            var tokens = antiforgery.GetAndStoreTokens(context);
            context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, 
                new CookieOptions() { HttpOnly = false });
        }

        return next(context);
    });
}

Richiedi convalida antifalsificazione

ValidateAntiForgeryToken è un filtro azione che può essere applicato a una singola azione, a un controller o a livello globale. Le richieste effettuate alle azioni con questo filtro applicato vengono bloccate a meno che la richiesta non includa un token antiforgery valido.

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> RemoveLogin(RemoveLoginViewModel account)
{
    ManageMessageId? message = ManageMessageId.Error;
    var user = await GetCurrentUserAsync();

    if (user != null)
    {
        var result = 
            await _userManager.RemoveLoginAsync(
                user, account.LoginProvider, account.ProviderKey);

        if (result.Succeeded)
        {
            await _signInManager.SignInAsync(user, isPersistent: false);
            message = ManageMessageId.RemoveLoginSuccess;
        }
    }

    return RedirectToAction(nameof(ManageLogins), new { Message = message });
}

L'attributo ValidateAntiForgeryToken richiede un token per le richieste ai metodi di azione contrassegnati, incluse le richieste HTTP GET. Se l'attributo ValidateAntiForgeryToken viene applicato attraverso i controller dell'app, può essere sovrascritto con l'attributo IgnoreAntiforgeryToken.

Nota

ASP.NET Core non supporta l'aggiunta automatica di token antiforgery alle richieste GET.

Convalidare automaticamente i token antiforgery solo per metodi HTTP non sicuri

Le app ASP.NET Core non generano token antiforgery per i metodi HTTP sicuri (GET, HEAD, OPTIONS e TRACE). Anziché applicare l'attributo ValidateAntiForgeryToken a livello generale per poi eseguirne l'override con gli attributi IgnoreAntiforgeryToken, è possibile usare l'attributo AutoValidateAntiforgeryToken. Questo attributo funziona in modo identico all'attributo ValidateAntiForgeryToken , ad eccezione del fatto che non richiede token per le richieste effettuate usando i metodi HTTP seguenti:

  • GET
  • HEAD
  • OPZIONI
  • TRACE

È consigliabile l'uso di AutoValidateAntiforgeryToken in modo ampio per scenari non API. Questo attributo garantisce che le azioni POST siano protette per impostazione predefinita. L'alternativa consiste nell'ignorare i token antiforgery per impostazione predefinita, a meno che ValidateAntiForgeryToken venga applicato ai singoli metodi di azione. In questo scenario è più probabile che un metodo di azione POST venga lasciato non protetto per errore, lasciando l'app vulnerabile agli attacchi CSRF. Tutti i POST devono inviare il token antiforgery.

Le API non hanno un meccanismo automatico per l'invio dellacookie parte non del token. L'implementazione dipende probabilmente dall'implementazione del codice client. Di seguito sono riportati alcuni esempi:

Esempio a livello di classe:

[Authorize]
[AutoValidateAntiforgeryToken]
public class ManageController : Controller
{

Esempio globale:

services.AddControllersWithViews(options =>
    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()));

Sovrascrivere gli attributi antiforgery globali o del controller

Il filtro IgnoreAntiforgeryToken viene usato per eliminare la necessità di un token antiforgery per una determinata azione (o controller). Quando applicato, questo filtro sovrascrive i filtri ValidateAntiForgeryToken e AutoValidateAntiforgeryToken specificati ad un livello superiore (a livello globale o in un controller).

[Authorize]
[AutoValidateAntiforgeryToken]
public class ManageController : Controller
{
    [HttpPost]
    [IgnoreAntiforgeryToken]
    public async Task<IActionResult> DoSomethingSafe(SomeViewModel model)
    {
        // no antiforgery token required
    }
}

Aggiornare i token dopo l'autenticazione

I token devono essere aggiornati dopo l'autenticazione dell'utente reindirizzando l'utente a una pagina di visualizzazione o Razor pagine.

JavaScript, AJAX e SPA

Nelle app tradizionali basate su HTML, i token antiforgery vengono passati al server tramite campi modulo nascosti. Nelle app moderne basate su JavaScript e nelle applicazioni a pagina singola, molte richieste vengono effettuate programmaticamente. Queste richieste AJAX possono usare altre tecniche (ad esempio intestazioni di richiesta o cookie) per inviare il token.

Se i cookie vengono usati per archiviare i token di autenticazione e per autenticare le richieste API nel server, CSRF è un potenziale problema. Se l'archiviazione locale viene usata per archiviare il token, la vulnerabilità CSRF potrebbe essere mitigata perché i valori dell'archiviazione locale non vengono inviati automaticamente al server con ogni richiesta. L'uso dell'archiviazione locale per archiviare il token antiforgery nel client e inviare il token come intestazione di richiesta è un approccio consigliato.

JavaScript

Usando JavaScript con visualizzazioni, il token può essere creato usando un servizio dall'interno della visualizzazione. Inserire il IAntiforgery servizio nella visualizzazione e chiamare GetAndStoreTokens:

@{
    ViewData["Title"] = "AJAX Demo";
}
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
@functions{
    public string GetAntiXsrfRequestToken()
    {
        return Xsrf.GetAndStoreTokens(Context).RequestToken;
    }
}

<input type="hidden" id="RequestVerificationToken" 
       name="RequestVerificationToken" value="@GetAntiXsrfRequestToken()">

<h2>@ViewData["Title"].</h2>
<h3>@ViewData["Message"]</h3>

<div class="row">
    <p><input type="button" id="antiforgery" value="Antiforgery"></p>
    <script>
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function() {
            if (xhttp.readyState == XMLHttpRequest.DONE) {
                if (xhttp.status == 200) {
                    alert(xhttp.responseText);
                } else {
                    alert('There was an error processing the AJAX request.');
                }
            }
        };

        document.addEventListener('DOMContentLoaded', function() {
            document.getElementById("antiforgery").onclick = function () {
                xhttp.open('POST', '@Url.Action("Antiforgery", "Home")', true);
                xhttp.setRequestHeader("RequestVerificationToken", 
                    document.getElementById('RequestVerificationToken').value);
                xhttp.send();
            }
        });
    </script>
</div>

Questo approccio elimina la necessità di gestire direttamente l'impostazione dei cookie dal server o di leggerli dal client.

L'esempio precedente usa JavaScript per leggere il valore del campo nascosto per l'intestazione POST AJAX.

JavaScript può anche accedere ai token nei cookie e usare il contenuto di cookie per creare un'intestazione con il valore del token.

context.Response.Cookies.Append("CSRF-TOKEN", tokens.RequestToken, 
    new Microsoft.AspNetCore.Http.CookieOptions { HttpOnly = false });

Supponendo che lo script richieda di inviare il token in un'intestazione denominata X-CSRF-TOKEN, configurare il servizio antiforgery per cercare l'intestazione X-CSRF-TOKEN :

services.AddAntiforgery(options => options.HeaderName = "X-CSRF-TOKEN");

L'esempio seguente usa JavaScript per effettuare una richiesta AJAX con l'intestazione appropriata:

function getCookie(cname) {
    var name = cname + "=";
    var decodedCookie = decodeURIComponent(document.cookie);
    var ca = decodedCookie.split(';');
    for (var i = 0; i < ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0) === ' ') {
            c = c.substring(1);
        }
        if (c.indexOf(name) === 0) {
            return c.substring(name.length, c.length);
        }
    }
    return "";
}

var csrfToken = getCookie("CSRF-TOKEN");

var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
    if (xhttp.readyState === XMLHttpRequest.DONE) {
        if (xhttp.status === 204) {
            alert('Todo item is created successfully.');
        } else {
            alert('There was an error processing the AJAX request.');
        }
    }
};
xhttp.open('POST', '/api/items', true);
xhttp.setRequestHeader("Content-type", "application/json");
xhttp.setRequestHeader("X-CSRF-TOKEN", csrfToken);
xhttp.send(JSON.stringify({ "name": "Learn C#" }));

AngularJS

AngularJS usa una convenzione per gestire CSRF. Se il server invia un cookie con il nome XSRF-TOKEN, il servizio AngularJS $http aggiunge il valore cookie a un'intestazione quando invia una richiesta al server. Questo processo è automatico. Il client non deve impostare l'intestazione in modo esplicito. Il nome dell'intestazione è X-XSRF-TOKEN. Il server deve rilevare questa intestazione e convalidarne il contenuto.

Affinché ASP.NET'API Core funzioni con questa convenzione nell'avvio dell'applicazione:

  • Configura l'app per fornire un token in un cookie denominato XSRF-TOKEN.
  • Configurare il servizio antiforgery per cercare un'intestazione denominata X-XSRF-TOKEN, ovvero il nome di intestazione predefinito di Angular per l'invio del token XSRF.
public void Configure(IApplicationBuilder app, IAntiforgery antiforgery)
{
    app.Use(next => context =>
    {
        string path = context.Request.Path.Value;

        if (
            string.Equals(path, "/", StringComparison.OrdinalIgnoreCase) ||
            string.Equals(path, "/index.html", StringComparison.OrdinalIgnoreCase))
        {
            var tokens = antiforgery.GetAndStoreTokens(context);
            context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, 
                new CookieOptions() { HttpOnly = false });
        }

        return next(context);
    });
}

public void ConfigureServices(IServiceCollection services)
{
    services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
}

Nota

Quando il token antiforgery viene fornito sia nell'intestazione della richiesta che nel contenuto del modulo, viene convalidato solo il token nell'intestazione.

autenticazione Windows e i cookie antifalsificazione

Quando si usa l'autenticazione di Windows, gli endpoint dell'applicazione devono essere protetti dagli attacchi CSRF nello stesso modo usato per i cookie. Il browser invia in modo implicito il contesto di autenticazione al server e quindi gli endpoint devono essere protetti dagli attacchi CSRF.

Estendere il sistema anti-contraffazione

Il tipo IAntiforgeryAdditionalDataProvider permette agli sviluppatori di espandere il comportamento del sistema anti-CSRF trasferendo dati aggiuntivi in ogni token. Il GetAdditionalData metodo viene chiamato ogni volta che viene generato un token di campo e il valore restituito viene incorporato all'interno del token generato. Un implementatore può restituire un timestamp, un nonce o qualsiasi altro valore e quindi chiamare ValidateAdditionalData per convalidare questi dati quando il token viene convalidato. Il nome utente del client è già incorporato nei token generati, quindi non è necessario includere queste informazioni. Se un token include dati supplementari ma non IAntiForgeryAdditionalDataProvider è configurato, i dati supplementari non vengono convalidati.

Risorse aggiuntive