Condividi tramite


Linee guida per la mitigazione delle minacce per ASP.NET Core Blazor rendering interattivo lato server.

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 9 di questo articolo.

Avviso

Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere i criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 9 di questo articolo.

Importante

Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.

Per la versione corrente, vedere la versione .NET 9 di questo articolo.

Questo articolo illustra come attenuare le minacce alla sicurezza in interactive server-side Blazor.

Le app adottano un modello di elaborazione dati con stato, in cui il server e il client mantengono una relazione di lunga durata. Lo stato persistente viene mantenuto da un circuito, che può estendersi anche sulle connessioni potenzialmente di lunga durata.

Quando un utente visita un sito, il server crea un circuito nella memoria del server. Il circuito indica al browser quale contenuto eseguire il rendering e risponde agli eventi, ad esempio quando l'utente seleziona un pulsante nell'interfaccia utente. Per eseguire queste azioni, un circuito richiama le funzioni JavaScript nel browser dell'utente e nei metodi .NET nel server. Questa interazione basata su JavaScript bidirezionale viene definita interoperabilità JavaScript (JS interop).

Poiché JS l'interoperabilità si verifica su Internet e il client usa un browser remoto, le app condividono la maggior parte dei problemi di sicurezza delle app Web. In questo argomento vengono descritte le minacce comuni alle app lato Blazor server e vengono fornite indicazioni per la mitigazione delle minacce incentrate sulle app con connessione Internet.

Negli ambienti vincolati, ad esempio all'interno di reti aziendali o intranet, alcune delle linee guida per la mitigazione sono:

  • Non si applica nell'ambiente vincolato.
  • Non vale il costo da implementare perché il rischio di sicurezza è basso in un ambiente vincolato.

Componenti server interattivi con compressione WebSocket abilitata

La compressione può esporre l'app ad attacchi a canale laterale contro la crittografia TLS durante la connessione, come gli attacchi CRIME e BREACH. Questi tipi di attacchi richiedono che il cyberattacker:

  • Forzare un browser a inviare richieste con un payload controllato dal cyberattacker a un sito vulnerabile tramite l'invio di moduli intersito o incorporando il sito all'interno di iframe di un altro sito.
  • Osservare la lunghezza della risposta compressa e crittografata in rete.

Affinché l'app sia vulnerabile, deve riflettere il payload del cyberattacker nella risposta, ad esempio scrivendo il percorso o la stringa di query nella risposta. Usando la lunghezza della risposta, il cyberattacker può "indovinare" qualsiasi informazione sulla risposta, ignorando la crittografia della connessione.

In generale, Blazor le app possono abilitare la compressione sulla connessione WebSocket con misure di sicurezza appropriate:

  • L'app può essere vulnerabile quando accetta contenuto dalla richiesta (ad esempio, il percorso o la stringa di query) che può essere influenzato da un cyberattacker e lo riproduce nel codice HTML della pagina o lo rende parte della risposta.

  • Blazor applica automaticamente le misure di sicurezza seguenti:

    • Quando la compressione è configurata, Blazor blocca automaticamente l'incorporamento dell'app in un iframe, che blocca la risposta iniziale (non compressa) dal server dal rendering e impedisce l'avvio della connessione WebSocket.

    • La restrizione sull'incorporamento dell'app in un iframe può essere rilassata. Tuttavia, la riduzione della restrizione espone l'app ad un attacco se il documento di incorporamento viene compromesso tramite una vulnerabilità di scripting intersito, poiché ciò fornisce al cyberattaccante un modo per eseguire l'attacco.

  • In genere per questo tipo di attacco, l'app deve riprodurre ripetutamente il contenuto nelle risposte in modo che il cyberattacker possa indovinare la risposta. Data la modalità Blazor di rendering (viene eseguito il rendering una sola volta e quindi produce diffs del contenuto solo per gli elementi modificati), questo risulta difficile da realizzare per un pirata informatico. Tuttavia, non è impossibile per un cyberattacker, quindi è necessario prestare attenzione a evitare di eseguire il rendering di informazioni riservate insieme a informazioni esterne che possono essere manipolate da un cyberattacker. Di seguito sono riportati alcuni esempi:

    • Eseguire il rendering delle informazioni personali nella pagina contemporaneamente al rendering dei dati del database aggiunti da un altro utente.

    • Rendering delle informazioni di identificazione personale sulla pagina contemporaneamente ai dati provenienti da un altro utente tramite JS interoperabilità o un servizio locale singleton sul server.

In generale, è consigliabile evitare di eseguire il rendering di componenti contenenti informazioni riservate insieme ai componenti che possono eseguire il rendering dei dati da origini non attendibili come parte dello stesso batch di rendering. Le origini non attendibili includono parametri di route, stringhe di query, dati di JS interoperabilità e qualsiasi altra origine di dati che un utente di terze parti può controllare (database, servizi esterni).

Stato condiviso

Le app sul lato Blazor server sono attive in memoria server e più sessioni di app sono ospitate nello stesso processo. Per ogni sessione dell'app, Blazor avvia un circuito con il proprio ambito contenitore di inserimento delle dipendenze, pertanto i servizi con ambito sono univoci per Blazor sessione.

Avviso

Non è consigliabile che le app sullo stesso server condividendo lo stato usino servizi singleton, a meno che non si presti estrema attenzione, poiché ciò può introdurre vulnerabilità di sicurezza, ad esempio perdite di dati dell'utente tra circuiti.

È possibile utilizzare i servizi singleton stateful nelle app Blazor se sono progettati specificamente per questo. Ad esempio, l'uso di una cache di memoria singleton è accettabile perché una cache di memoria richiede una chiave per accedere a una determinata voce. Supponendo che gli utenti non abbiano il controllo sulle chiavi della cache usate nella cache, lo stato archiviato nella cache non trapela tra i circuiti.

Per indicazioni generali sulla gestione dello stato, vedere ASP.NET Core Blazor gestione dello stato.

IHttpContextAccessor/HttpContext

Per altre informazioni, vedere IHttpContextAccessor/HttpContext nelle app ASP.NET Core Blazor.

Esaurimento delle risorse

L'esaurimento delle risorse può verificarsi quando un client interagisce con il server e fa sì che il server consumi risorse eccessive. L'utilizzo eccessivo delle risorse influisce principalmente su:

Gli attacchi Denial of Service (DoS) in genere cercano di esaurire le risorse di un'app o di un server. Tuttavia, l'esaurimento delle risorse non è necessariamente il risultato di un attacco al sistema. Ad esempio, le risorse limitate possono essere esaurite a causa di una domanda elevata degli utenti. DoS è illustrato più avanti nella sezione DoS.

Le risorse esterne al Blazor framework, come database e handle di file (utilizzati per leggere e scrivere file), possono anche subire l'esaurimento delle risorse. Per altre informazioni, vedere ASP.NET Procedure consigliate di base.

CPU (Unità Centrale di Elaborazione)

L'esaurimento della CPU può verificarsi quando uno o più client forzano il server a eseguire un utilizzo intensivo della CPU.

Si consideri, ad esempio, un'app che calcola un numero Fibonnacci. Un numero Fibonnacci viene prodotto da una sequenza Fibonnacci, dove ogni numero nella sequenza è la somma dei due numeri precedenti. La quantità di lavoro necessaria per raggiungere la risposta dipende dalla lunghezza della sequenza e dalle dimensioni del valore iniziale. Se l'app non pone limiti alla richiesta di un client, i calcoli a elevato utilizzo di CPU possono dominare il tempo della CPU e diminuire le prestazioni di altre attività. Un consumo eccessivo di risorse è un problema di sicurezza che influisce sulla disponibilità.

L'esaurimento della CPU è un problema per tutte le app pubbliche. Nelle normali app Web, le richieste e le connessioni scadono come misura preventiva, ma le app Blazor non forniscono le stesse misure preventive. Blazor le app devono includere controlli e limiti appropriati prima di eseguire un lavoro potenzialmente intensivo della CPU.

Memoria

L'esaurimento della memoria può verificarsi quando uno o più client forzano il server a utilizzare una grande quantità di memoria.

Si consideri, ad esempio, un'app con un componente che accetta e visualizza un elenco di elementi. Se l'app Blazor non pone limiti al numero di elementi consentiti o al numero di elementi di cui viene eseguito il rendering al client, l'elaborazione e il rendering a elevato utilizzo di memoria possono dominare la memoria del server fino al punto in cui le prestazioni del server risentono. Il server potrebbe arrestarsi in modo anomalo o rallentare fino al punto in cui sembra che si sia verificato un arresto anomalo.

Si consideri lo scenario seguente per la gestione e la visualizzazione di un elenco di elementi relativi a uno scenario di esaurimento della memoria potenziale nel server:

  • Gli elementi di una proprietà o di un List<T> campo utilizzano la memoria del server. Se l'app consente all'elenco di elementi di crescere senza vincoli, è possibile che il server esaurisca la memoria. L'esaurimento della memoria causa la fine della sessione corrente (arresto anomalo) e tutte le sessioni simultanee in tale istanza del server ricevono un'eccezione di memoria insufficiente. Per evitare che si verifichi questo scenario, l'app deve usare una struttura di dati che impone un limite di elementi per gli utenti simultanei.
  • Se non viene usato uno schema di paging per il rendering, il server usa memoria aggiuntiva per gli oggetti che non sono visibili nell'interfaccia utente. Senza un limite al numero di elementi, le richieste di memoria possono esaurire la memoria del server disponibile. Per evitare questo scenario, usare uno degli approcci seguenti:
    • Usare elenchi impaginati durante il rendering.
    • Visualizza solo i primi 100-1.000 elementi e richiede all'utente di immettere i criteri di ricerca per trovare elementi oltre gli elementi visualizzati.
    • Per uno scenario di rendering più avanzato, implementare elenchi o griglie che supportano la virtualizzazione. Usando la virtualizzazione, elenca solo un subset di elementi attualmente visibili all'utente. Quando l'utente interagisce con la barra di scorrimento nell'interfaccia utente, il componente esegue il rendering solo degli elementi necessari per la visualizzazione. Gli elementi che non sono attualmente necessari per la visualizzazione possono essere mantenuti nell'archiviazione secondaria, che è l'approccio ideale. Gli elementi non visualizzati possono anche essere conservati in memoria, il che è meno ottimale.

Nota

Blazor include il supporto predefinito per la virtualizzazione. Per ulteriori informazioni, vedere ASP.NET Core Razor virtualizzazione dei componenti.

Blazorle app offrono un modello di programmazione simile ad altri framework dell'interfaccia utente per app con stato, ad esempio WPF, Windows Form o Blazor WebAssembly. La differenza principale è che in diversi framework dell'interfaccia utente la memoria utilizzata dall'app appartiene al client e influisce solo su quel singolo client. Ad esempio, un'app Blazor WebAssembly viene eseguita interamente nel client e usa solo le risorse di memoria client. Per un'app sul lato Blazor del server, la memoria utilizzata dall'app appartiene al server ed è condivisa tra i client dell'istanza del server.

Le richieste di memoria lato server sono una considerazione per tutte le app Blazor lato server. Tuttavia, la maggior parte delle app Web è senza stato e la memoria usata durante l'elaborazione di una richiesta viene rilasciata quando viene restituita la risposta. Come raccomandazione generale, non consentire ai client di allocare una quantità illimitata di memoria, come in qualsiasi altra app lato server che mantiene connessioni client permanenti. La memoria utilizzata da un'app lato Blazor server viene mantenuta per un periodo di tempo maggiore rispetto a una singola richiesta.

Nota

Durante lo sviluppo, è possibile usare un profiler o una traccia acquisita per valutare le richieste di memoria dei client. Un profiler o una traccia non acquisisce la memoria allocata a un client specifico. Per acquisire il consumo di memoria di un client specifico durante lo sviluppo, bisogna acquisire un dump ed esaminare la richiesta di memoria di tutti gli oggetti radicati nel circuito personale di un utente.

Connessioni client

L'esaurimento delle connessioni può verificarsi quando uno o più client aprono troppe connessioni simultanee al server, impedendo ad altri client di stabilire nuove connessioni.

Blazor i client stabiliscono una singola connessione per sessione e mantengono aperta la connessione finché la finestra del browser è aperta. Data la natura persistente delle connessioni e la natura con stato mantenuto delle app sul lato server Blazor, l'esaurimento delle connessioni è un rischio più grande per la disponibilità dell'app.

Non esiste alcun limite al numero di connessioni per utente per un'app. Se l'app richiede un limite di connessione, adottare uno o più degli approcci seguenti:

  • Richiedere l'autenticazione, che limita naturalmente la capacità di utenti non autorizzati di connettersi all'app. Affinché questo scenario sia efficace, è necessario impedire agli utenti di effettuare il provisioning di nuovi utenti su richiesta.
  • Limitare il numero di connessioni per utente. La limitazione delle connessioni può essere eseguita tramite gli approcci seguenti. Prestare attenzione a consentire agli utenti legittimi di accedere all'app (ad esempio, quando viene stabilito un limite di connessione in base all'indirizzo IP del client).
    • Livello applicazione
      • Estendibilità del routing degli endpoint.
      • Richiedere l'autenticazione per connettersi all'app e tenere traccia delle sessioni attive per utente.
      • Rifiutare nuove sessioni al raggiungimento di un limite.
      • Proxy delle connessioni WebSocket a un'app tramite l'uso di un proxy, come il Service di Azure, che esegue il multiplexing delle connessioni dai client a un'app. In questo modo un'app ha una capacità di connessione maggiore di quella che un singolo client può stabilire, impedendo a un client di esaurire le connessioni al server.
    • Livello server: usare un proxy o un gateway davanti all'app.
  • Richiedere l'autenticazione, che limita naturalmente la capacità di utenti non autorizzati di connettersi all'app. Affinché questo scenario sia efficace, è necessario impedire agli utenti di effettuare il provisioning di nuovi utenti su richiesta.
  • Limitare il numero di connessioni per utente. La limitazione delle connessioni può essere eseguita tramite gli approcci seguenti. Prestare attenzione a consentire agli utenti legittimi di accedere all'app (ad esempio, quando viene stabilito un limite di connessione in base all'indirizzo IP del client).
    • Livello applicazione
      • Estendibilità del routing degli endpoint.
      • Richiedere l'autenticazione per connettersi all'app e tenere traccia delle sessioni attive per utente.
      • Rifiutare nuove sessioni al raggiungimento di un limite.
      • Connessioni WebSocket all'app tramite l'uso di un proxy, come il servizio di Azure, che esegue il multiplex delle connessioni dai client all'app. In questo modo un'app ha una capacità di connessione maggiore di quella che un singolo client può stabilire, impedendo a un client di esaurire le connessioni al server.
    • Livello server

Attacchi di negazione del servizio (DoS)

Gli attacchi Denial of Service (DoS) comportano un client che causa l'esaurimento di una o più risorse del server che rendono l'app non disponibile. Blazor Le app includono i limiti predefiniti e si basano su altri limiti di ASP.NET Core e SignalR impostati per CircuitOptions proteggere da attacchi DoS:

Per altre informazioni ed esempi di codifica della configurazione, vedere gli articoli seguenti:

Interazioni con il browser (client)

Un client interagisce con il server tramite l'invio JS di eventi di interoperabilità e il completamento del rendering. JS la comunicazione di interoperabilità va in entrambi i modi tra JavaScript e .NET:

  • Gli eventi del browser vengono inviati dal client al server in modo asincrono.
  • Il server risponde in modo asincrono ripristinando l'interfaccia utente in base alle esigenze.

Funzioni JavaScript richiamate da .NET

Per le chiamate da metodi .NET a JavaScript:

  • Tutte le chiamate hanno un timeout configurabile dopo il quale hanno esito negativo, restituendo un oggetto OperationCanceledException al chiamante.
  • Il risultato di una chiamata JavaScript non può essere considerato attendibile. Il Blazor client dell'app in esecuzione nel browser cerca la funzione JavaScript da richiamare. La funzione viene richiamata e viene generato il risultato o un errore. Un client dannoso può tentare di:
    • Causa un problema nell'app restituendo un errore dalla funzione JavaScript.
    • Indurre un comportamento imprevisto nel server restituendo un risultato imprevisto dalla funzione JavaScript.

Adottare le precauzioni seguenti per proteggersi dagli scenari precedenti:

  • Incorpora le chiamate di interoperabilità JS all'interno delle istruzioni try-catch per tenere conto degli errori che possono verificarsi durante le invocazioni. Per ulteriori informazioni, vedere Gestire gli errori nelle app ASP.NET Core.
  • Convalidare i dati restituiti dalle JS chiamate di interoperabilità, inclusi i messaggi di errore, prima di eseguire qualsiasi azione.

Metodi .NET richiamati dal browser

Non considerare attendibili le chiamate da JavaScript ai metodi .NET. Quando un metodo .NET viene esposto a JavaScript, considerare come viene richiamato il metodo .NET:

  • Considerare qualsiasi metodo .NET esposto a JavaScript come endpoint pubblico per l'app.
    • Convalidare l'input.
      • Assicurarsi che i valori siano compresi negli intervalli previsti.
      • Assicurarsi che l'utente disponga dell'autorizzazione per eseguire l'azione richiesta.
    • Non allocare una quantità eccessiva di risorse come parte della chiamata al metodo .NET. Ad esempio, eseguire controlli e applicare limiti all'uso della CPU e della memoria.
    • Tenere conto che i metodi statici e di istanza possono essere esposti ai client JavaScript. Evitare di condividere lo stato tra le sessioni a meno che la progettazione non chiami la condivisione dello stato con vincoli appropriati.
      • Per i metodi di istanza esposti tramite gli oggetti DotNetObjectReference che sono originariamente creati tramite iniezione delle dipendenze (DI), gli oggetti devono essere registrati come oggetti con scopo. Questo vale per qualsiasi servizio DI utilizzato dall'app.
      • Per i metodi statici, evitare di stabilire uno stato che non può essere confinato al client, a meno che l'app non condivida in modo esplicito lo stato tra tutti gli utenti in un'istanza del server.
    • Evitare di passare i dati forniti dall'utente nei parametri alle chiamate JavaScript. Se il passaggio di dati nei parametri è assolutamente necessario, assicurarsi che il codice JavaScript gestisca il passaggio dei dati senza introdurre vulnerabilità XSS (Cross-Site Scripting). Ad esempio, non scrivere dati forniti dall'utente nel DOM impostando la innerHTML proprietà di un elemento. Prendere in considerazione l'uso di Content Security Policy (CSP) per disabilitare eval e altre primitive JavaScript non sicure. Per altre informazioni, vedere Applicare criteri di sicurezza del contenuto per ASP.NET Core Blazor e linee guida di riferimento CSP di MDN.
  • Evitare di implementare un'invio personalizzato delle chiamate .NET al di sopra dell'implementazione di invio del framework. L'esposizione di metodi .NET al browser è uno scenario avanzato, non consigliato per lo sviluppo generale Blazor .

Eventi

Gli eventi forniscono un punto di ingresso a un'app. Le stesse regole per proteggere gli endpoint nelle app Web si applicano alla gestione degli eventi nelle Blazor app. Un client malintenzionato può inviare qualsiasi dato che desidera come payload per un evento.

Ad esempio:

  • Un evento di modifica per un oggetto <select> potrebbe inviare un valore che non rientra nelle opzioni presentate dall'app al client.
  • Un <input> oggetto potrebbe inviare dati di testo al server, ignorando la convalida lato client.

L'app deve convalidare i dati per qualsiasi evento gestito dall'app. I Blazor componenti dei moduli del framework eseguono convalide di base. Se l'app usa componenti di moduli personalizzati, è necessario scrivere codice personalizzato per convalidare i dati degli eventi in base alle esigenze.

Gli eventi sono asincroni, quindi è possibile inviare più eventi al server prima che l'app abbia tempo per reagire generando un nuovo rendering. Ciò comporta alcune implicazioni per la sicurezza da considerare. La limitazione delle azioni client nell'app deve essere eseguita all'interno dei gestori eventi e non dipendere dallo stato corrente della vista renderizzata.

Si consideri un componente del contatore che dovrebbe consentire a un utente di incrementare un contatore massimo di tre volte. Il pulsante per incrementare il contatore è condizionalmente basato sul valore di count:

<p>Count: @count</p>

@if (count < 3)
{
    <button @onclick="IncrementCount" value="Increment count" />
}

@code 
{
    private int count = 0;

    private void IncrementCount()
    {
        count++;
    }
}

Un client può inviare uno o più eventi di incremento prima che il framework produa un nuovo rendering di questo componente. Il risultato è che l'oggetto count può essere incrementato più di tre volte dall'utente perché il pulsante non viene rimosso dall'interfaccia utente abbastanza rapidamente. Il modo corretto per raggiungere il limite di tre count incrementi è illustrato nell'esempio seguente:

<p>Count: @count</p>

@if (count < 3)
{
    <button @onclick="IncrementCount" value="Increment count" />
}

@code 
{
    private int count = 0;

    private void IncrementCount()
    {
        if (count < 3)
        {
            count++;
        }
    }
}

Aggiungendo il controllo if (count < 3) { ... } all'interno del gestore, la decisione di aumentare count è basata sullo stato corrente dell'app. La decisione non è basata sullo stato dell'interfaccia utente come nell'esempio precedente, che potrebbe essere temporaneamente obsoleto.

Proteggere contro più spedizioni

Se un callback di eventi richiama un'operazione a esecuzione prolungata in modo asincrono, ad esempio il recupero di dati da un servizio esterno o un database, è consigliabile usare una protezione. La protezione può impedire all'utente di accodare più operazioni mentre l'operazione è in corso con feedback visivo. Il codice componente seguente imposta isLoading su true mentre DataService.GetDataAsync ottiene i dati dal server. Mentre isLoading è true, il pulsante è disabilitato nell'interfaccia utente:

<button disabled="@isLoading" @onclick="UpdateData">Update</button>

@code {
    private bool isLoading;
    private Data[] data = Array.Empty<Data>();

    private async Task UpdateData()
    {
        if (!isLoading)
        {
            isLoading = true;
            data = await DataService.GetDataAsync(DateTime.Now);
            isLoading = false;
        }
    }
}

Il modello di protezione illustrato nell'esempio precedente funziona se l'operazione in background viene eseguita in modo asincrono con il async-await modello .

Annullare in anticipo ed evitare l'uso dopo l'eliminazione

Oltre a usare una protezione come descritto nella sezione Proteggere da più invii, è consigliabile usare un CancellationToken per annullare le operazioni a esecuzione prolungata quando il componente viene smaltito. Questo approccio offre il vantaggio aggiunto di evitare l'uso dopo l'eliminazione nei componenti:

@implements IDisposable

...

@code {
    private readonly CancellationTokenSource TokenSource = 
        new CancellationTokenSource();

    private async Task UpdateData()
    {
        ...

        data = await DataService.GetDataAsync(DateTime.Now, TokenSource.Token);

        if (TokenSource.Token.IsCancellationRequested)
        {
           return;
        }

        ...
    }

    public void Dispose()
    {
        TokenSource.Cancel();
    }
}

Evitare eventi che producono grandi quantità di dati

Alcuni eventi DOM, ad esempio oninput o onscroll, possono produrre una grande quantità di dati. Evitare di usare questi eventi nel server lato Blazor server.

Indicazioni aggiuntive sulla sicurezza

Le linee guida per la protezione delle app core ASP.NET si applicano alle app lato Blazor server e sono illustrate nelle sezioni seguenti di questo articolo:

Registrazione e dati sensibili

JS le interazioni di interoperabilità tra il client e il server vengono registrate nei registri del server con ILogger istanze. Blazor evita di registrare informazioni riservate, ad esempio eventi reali o JS input e output di interoperabilità.

Quando si verifica un errore nel server, il framework invia una notifica al client e rimuove la sessione. Il client riceve un messaggio di errore generico che può essere visualizzato negli strumenti di sviluppo del browser.

L'errore sul lato client non include lo stack di chiamate e non fornisce dettagli sulla causa dell'errore, ma i log del server contengono tali informazioni. A scopo di sviluppo, le informazioni riservate sugli errori possono essere rese disponibili al client abilitando errori dettagliati.

Avviso

L'esposizione di informazioni sugli errori ai client su Internet è un rischio per la sicurezza che deve essere sempre evitato.

Proteggere le informazioni in transito con HTTPS

Blazor utilizza SignalR per la comunicazione tra il client e il server. Blazor utilizza normalmente il trasporto che SignalR negozia, che in genere è WebSocket.

Blazor non garantisce l'integrità e la riservatezza dei dati inviati tra il server e il client. Usare sempre HTTPS.

Cross-site scripting (XSS)

Lo scripting tra siti (XSS) consente a un'entità non autorizzata di eseguire logica arbitraria nel contesto del browser. Un'app compromessa potrebbe potenzialmente eseguire codice arbitrario nel client. La vulnerabilità può essere usata per eseguire potenzialmente una serie di azioni dannose sul server:

  • Inviare eventi falsi/non validi al server.
  • Mancato completamento del rendering o renderizzazione non valida.
  • Evitare l'invio dei completamenti di rendering.
  • Inviare chiamate di interoperabilità da JavaScript a .NET.
  • Modificare la risposta delle chiamate di interoperabilità da .NET a JavaScript.
  • Evitare di inviare .NET ai JS risultati di interoperabilità.

Il Blazor framework esegue i passaggi per proteggersi da alcune delle minacce precedenti:

  • Interrompe la produzione di nuovi aggiornamenti dell'interfaccia utente se il client non riconosce i batch di rendering. Configurato con CircuitOptions.MaxBufferedUnacknowledgedRenderBatches.
  • Imposta un timeout per qualsiasi chiamata da .NET a JavaScript dopo un minuto se non riceve una risposta dal client. Configurato con CircuitOptions.JSInteropDefaultCallTimeout.
  • Esegue la convalida di base su tutti gli input provenienti dal browser durante l'interoperabilità JS.
    • I riferimenti .NET sono validi e del tipo previsto dal metodo .NET.
    • I dati non sono corrotti.
    • Il numero corretto di argomenti per il metodo è presente nel payload.
    • Gli argomenti o i risultati possono essere deserializzati correttamente prima di richiamare il metodo .
  • Esegue la convalida di base in tutti gli input provenienti dal browser da eventi inviati:
    • L'evento ha un tipo valido.
    • I dati per l'evento possono essere deserializzati.
    • All'evento è associato un gestore eventi.

Oltre alle misure di sicurezza implementate dal framework, l'app deve essere codificata dallo sviluppatore per proteggersi dalle minacce e intraprendere azioni appropriate:

  • Convalidare sempre i dati durante la gestione degli eventi.
  • Eseguire un'azione appropriata quando si ricevono dati non validi:
    • Ignora i dati e ritorna. Ciò consente all'app di continuare l'elaborazione delle richieste.
    • Se l'app determina che l'input non è valido e non può essere prodotto da un client legittimo, lanciare un'eccezione. Il lancio di un'eccezione abbatte il circuito e termina la sessione.
  • Non considerare attendibile il messaggio di errore fornito dai completamenti batch di rendering inclusi nei log. L'errore viene fornito dal client e in genere non può essere considerato attendibile, perché il client potrebbe essere compromesso.
  • Non fidarti dell'input nelle JS chiamate di interoperabilità tra metodi JavaScript e .NET in entrambe le direzioni.
  • L'app è responsabile della convalida della validità del contenuto degli argomenti e dei risultati, anche se gli argomenti o i risultati sono deserializzati correttamente.

Affinché esista una vulnerabilità XSS, l'app deve incorporare l'input dell'utente nella pagina sottoposta a rendering. Blazor esegue un passaggio in fase di compilazione in cui il markup in un .razor file viene trasformato in logica C# procedurale. In fase di esecuzione, la logica C# compila un albero di rendering che descrive gli elementi, il testo e i componenti figlio. Questa operazione viene applicata al DOM del browser attraverso una sequenza di istruzioni JavaScript (o viene serializzata in HTML nel caso del pre-rendering):

  • L'input dell'utente sottoposto a rendering tramite la sintassi normale Razor ( ad esempio , @someStringValue) non espone una vulnerabilità XSS perché la Razor sintassi viene aggiunta al DOM tramite comandi che possono scrivere solo testo. Anche se il valore include markup HTML, il valore viene visualizzato come testo statico. Quando si esegue il prerendering, l'output viene codificato in HTML, il che visualizza anche il contenuto come testo statico.
  • Gli autori di componenti possono creare componenti in C# senza usare Razor. L'autore del componente è responsabile dell'uso delle API corrette durante l'emissione dell'output. Ad esempio, usare builder.AddContent(0, someUserSuppliedString) e nonbuilder.AddMarkupContent(0, someUserSuppliedString), perché quest'ultimo potrebbe creare una vulnerabilità XSS.
  • L'input dell'utente sottoposto a rendering tramite la sintassi normale Razor ( ad esempio , @someStringValue) non espone una vulnerabilità XSS perché la Razor sintassi viene aggiunta al DOM tramite comandi che possono scrivere solo testo. Anche se il valore include markup HTML, il valore viene visualizzato come testo statico. Quando si esegue il pre-rendering, l'output è codificato in HTML, visualizzando il contenuto come testo statico.
  • I tag di script non sono consentiti e non devono essere inclusi nell'albero di rendering del componente dell'app. Se un tag di script viene incluso nel markup di un componente, viene generato un errore in fase di compilazione.
  • Gli autori di componenti possono creare componenti in C# senza usare Razor. L'autore del componente è responsabile dell'uso delle API corrette durante l'emissione dell'output. Ad esempio, usare builder.AddContent(0, someUserSuppliedString) e nonbuilder.AddMarkupContent(0, someUserSuppliedString), perché quest'ultimo potrebbe creare una vulnerabilità XSS.

Valutare la possibilità di attenuare ulteriormente le vulnerabilità XSS. Ad esempio, implementare un criterio di sicurezza del contenuto restrittivo (CSP). Per altre informazioni, vedere Applicare criteri di sicurezza del contenuto per ASP.NET Core Blazor e linee guida di riferimento CSP di MDN.

Per altre informazioni, vedere Prevent Cross-Site Scripting (XSS) in ASP.NET Core.

Protezione tra origini differenti

Gli attacchi tra origini coinvolgono un client da un'origine diversa che esegue un'azione sul server. L'azione dannosa è in genere una richiesta GET o un modulo POST (Cross-Site Request Forgery, CSRF), ma è anche possibile aprire un WebSocket dannoso. Blazor le app offrono le stesse garanzie che qualsiasi altra SignalR app che usa l'offerta del protocollo hub:

  • È possibile accedere alle app tra le origini, a meno che non vengano adottate misure aggiuntive per impedirlo. Per disabilitare l'accesso tra le origini, disabilitare CORS nell'endpoint aggiungendo il middleware CORS alla pipeline e aggiungendo DisableCorsAttribute al metadati dell'endpoint Blazor o limitare il set di origini consentite configurando SignalR per la condivisione di risorse tra le origini. Per indicazioni sulle restrizioni relative all'origine WebSocket, vedere Supporto di WebSocket in ASP.NET Core.
  • Se CORS è abilitato, potrebbero essere necessari passaggi aggiuntivi per proteggere l'app a seconda della configurazione CORS. Se CORS è abilitato a livello globale, CORS può essere disabilitato per l'hub BlazorSignalR aggiungendo i metadati DisableCorsAttribute ai metadati dell'endpoint dopo aver chiamato MapBlazorHub nel generatore di route dell'endpoint.

Per altre informazioni, vedere Prevenire attacchi tramite richieste intersito false (XSRF/CSRF) in ASP.NET Core.

Intercettazione di clic

Il click-jacking comporta il rendering di un sito come <iframe> all'interno di un sito proveniente da un'origine diversa per ingannare l'utente affinché esegua azioni sul sito sotto attacco.

Per proteggere un'app dal rendering all'interno di un <iframe>, usare Criteri di sicurezza del contenuto (CSP) e l'intestazione X-Frame-Options . Per la sintassi CSP, vedere le linee guida di riferimento CSP di MDN.

Per ulteriori informazioni, vedi le seguenti risorse:

Aprire i reindirizzamenti

All'avvio di una sessione dell'app, il server esegue la convalida di base degli URL inviati come parte dell'avvio della sessione. Il framework verifica che l'URL di base sia un elemento padre dell'URL corrente prima di stabilire il circuito. Non vengono eseguiti controlli aggiuntivi dal framework.

Quando un utente seleziona un collegamento nel client, l'URL per il collegamento viene inviato al server, che determina l'azione da eseguire. Ad esempio, l'app può eseguire uno spostamento sul lato client o indicare al browser di passare alla nuova posizione.

I componenti possono anche attivare le richieste di spostamento a livello di codice tramite l'uso di NavigationManager. In questi scenari, l'app potrebbe eseguire uno spostamento sul lato client o indicare al browser di passare alla nuova posizione.

I componenti devono:

  • Evitare di usare l'input dell'utente come parte degli argomenti della chiamata di navigazione.
  • Convalidare gli argomenti per assicurarsi che la destinazione sia consentita dall'app.

In caso contrario, un utente malintenzionato può forzare il browser a passare a un sito controllato da cyberattacker. In questo scenario, il cyberattacker riesce a far sì che l'app utilizzi un input utente come parte dell'invocazione del metodo NavigationManager.NavigateTo.

Questo consiglio si applica anche quando si esegue il rendering dei collegamenti come parte dell'app:

  • Se possibile, usare collegamenti relativi.
  • Verificare che le destinazioni dei collegamenti assoluti siano valide prima di includerle in una pagina.

Per altre informazioni, vedere Impedire attacchi di reindirizzamento aperti in ASP.NET Core.

Elenco di controllo relativo alla sicurezza

L'elenco seguente di considerazioni sulla sicurezza non è completo:

  • Convalidare gli argomenti dagli eventi.
  • Convalidare gli input e i risultati dalle JS chiamate di interoperabilità.
  • Evitare di usare (o convalidare JS in anticipo) l'input dell'utente per le chiamate di interoperabilità .NET.
  • Impedire che il client allocchi una quantità di memoria illimitata.
  • Proteggere da più invii.
  • Annullare le operazioni a esecuzione prolungata quando il componente viene eliminato.
  • Evitare eventi che producono grandi quantità di dati.
  • Evitare di usare l'input dell'utente come parte delle chiamate a NavigationManager.NavigateTo e, se inevitabile, convalidare l'input dell'utente per gli URL rispetto a un set di origini consentite.
  • Non prendere decisioni di autorizzazione in base allo stato dell'interfaccia utente, ma solo dallo stato del componente.
  • Prendere in considerazione l'uso di Criteri di sicurezza del contenuto (CSP) per proteggersi dagli attacchi XSS. Per altre informazioni, vedere Applicare criteri di sicurezza del contenuto per ASP.NET Core Blazor e linee guida di riferimento CSP di MDN.
  • È consigliabile usare CSP e X-Frame-Options per proteggersi dal click-jacking.
  • Assicurarsi che le impostazioni CORS siano appropriate quando si abilita CORS o si disabilita in modo esplicito CORS per Blazor le app.
  • Testare per assicurarsi che i limiti lato server per l'app Blazor forniscano un'esperienza utente accettabile senza livelli di rischio inaccettabili.