Linee guida per la mitigazione delle minacce per ASP.NET rendering lato server interattivo Core Blazor
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 interoperabilità).
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 side channel contro la crittografia TLS della connessione, ad esempio CRIME e BREACH attacchi. Questi tipi di attacchi richiedono che il cyberattacker:
- Forzare un browser a inviare richieste con un payload i controlli cyberattacker a un sito vulnerabile tramite la pubblicazione di moduli tra siti o incorporando il sito all'interno di un 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 attaccare se il documento di incorporamento viene compromesso tramite una vulnerabilità di scripting intersito, in quanto fornisce al cyberattacker 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 è difficile per un cyberattacker da realizzare. 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 personali nella pagina contemporaneamente ai dati provenienti da un altro utente tramite JS interoperabilità o un servizio singleton locale nel 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 nello stesso stato di condivisione server usino servizi singleton, a meno che non venga eseguita un'estrema attenzione, in quanto ciò può introdurre vulnerabilità di sicurezza, ad esempio la perdita dello stato utente tra circuiti.
È possibile usare i servizi singleton con stato nelle Blazor app se sono progettati specificamente per esso. 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 con la cache, lo stato archiviato nella cache non perde i circuiti.
Per indicazioni generali sulla gestione dello stato, vedere ASP.NET Gestione dello stato coreBlazor.
IHttpContextAccessor
/HttpContext
nei Razor componenti
IHttpContextAccessor è necessario evitare il rendering interattivo perché non è disponibile un valore valido HttpContext
.
IHttpContextAccessor può essere usato per i componenti di cui viene eseguito il rendering statico nel server. Tuttavia, è consigliabile evitarlo, se possibile.
HttpContext può essere usato come parametro a catena solo nei componenti radice sottoposti a rendering statico per attività generali, ad esempio l'ispezione e la modifica di intestazioni o altre proprietà nel App
componente (Components/App.razor
). Il valore è sempre null
per il rendering interattivo.
[CascadingParameter]
public HttpContext? HttpContext { get; set; }
Per gli scenari in cui HttpContext è necessario nei componenti interattivi, è consigliabile fluire i dati tramite lo stato del componente persistente dal server. Per altre informazioni, vedere ASP.NET core server-side e Blazor Web App altri scenari di sicurezza.
Non usare IHttpContextAccessor/HttpContext direttamente o indirettamente nei Razor componenti delle app lato Blazor server. Blazor le app vengono eseguite all'esterno del contesto della pipeline core ASP.NET. Non HttpContext è garantito che sia disponibile all'interno di IHttpContextAccessore HttpContext non sia garantito che contenga il contesto che ha avviato l'app Blazor .
L'approccio consigliato per passare lo stato della richiesta all'app consiste nell'usare Blazor i parametri del componente radice durante il rendering iniziale dell'app. In alternativa, l'app può copiare i dati in un servizio con ambito nell'evento del ciclo di vita di inizializzazione del componente radice da usare nell'app. Per altre informazioni, vedere ASP.NET core server-side e Blazor Web App altri scenari di sicurezza.
Un aspetto critico della sicurezza lato Blazor server è che l'utente collegato a un determinato circuito potrebbe essere aggiornato a un certo punto dopo che il Blazor circuito è stato stabilito, ma IHttpContextAccessornon viene aggiornato. Per altre informazioni sulla gestione di questa situazione con i servizi personalizzati, vedere ASP.NET scenari di sicurezza aggiuntivi e Blazor Web App lato server core.
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, ad esempio database e handle di file (usati per leggere e scrivere file), possono verificarsi anche l'esaurimento delle risorse. Per altre informazioni, vedere ASP.NET Procedure consigliate di base.
CPU
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 i timeout delle connessioni come protezione, ma Blazor le app non forniscono le stesse misure di sicurezza. 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 riprodotti possono anche essere mantenuti in memoria, che è meno ideale.
Nota
Blazor include il supporto predefinito per la virtualizzazione. Per altre informazioni, vedere ASP.NET Virtualizzazione dei componenti coreRazor.
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 lato Blazor server, la memoria utilizzata dall'app appartiene al server e viene condivisa tra i client nell'istanza del server.
Le richieste di memoria lato server sono una considerazione per tutte le app lato Blazor 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à di memoria non associato come in qualsiasi altra app lato server che rende persistenti le connessioni client. 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 l'uso della memoria di un client specifico durante lo sviluppo, acquisire un dump ed esaminare la richiesta di memoria di tutti gli oggetti rooted nel circuito 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 delle app lato Blazor server, l'esaurimento delle connessioni è un rischio maggiore 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 WebSocket connessioni a un'app tramite l'uso di un proxy, ad esempio il servizio di Azure SignalR 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. Ad esempio, app Azure lication Gateway è un servizio di bilanciamento del carico del traffico Web (OSI livello 7) che consente di gestire il traffico verso le applicazioni Web. Per altre informazioni, vedere Panoramica del supporto di WebSocket in gateway applicazione.
- Anche se il polling lungo è supportato per Blazor le app, che consentirebbe l'adozione di Frontdoor di Azure, WebSocket è il protocollo di trasporto consigliato. A partire da settembre 2024, Frontdoor di Azure non supporta WebSocket, ma il supporto per WebSocket è in considerazione. Per altre informazioni, vedere Supporto delle connessioni WebSocket in Frontdoor di Azure.
- Livello applicazione
- 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 WebSocket connessioni a un'app tramite l'uso di un proxy, ad esempio il servizio di Azure SignalR 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.
- Anche se il polling lungo è supportato per Blazor le app, WebSocket è il protocollo di trasporto consigliato. È consigliabile selezionare un proxy o un gateway che supporti WebSocket.
- Livello applicazione
Attacchi Denial of Service (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 ASP.NET Core e SignalR limiti impostati per CircuitOptions proteggere da attacchi DoS:
- CircuitOptions.DisconnectedCircuitMaxRetained
- CircuitOptions.DisconnectedCircuitRetentionPeriod
- CircuitOptions.JSInteropDefaultCallTimeout
- CircuitOptions.MaxBufferedUnacknowledgedRenderBatches
- HubConnectionContextOptions.MaximumReceiveMessageSize
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.
- Esiste un timeout predefinito per le chiamate (CircuitOptions.JSInteropDefaultCallTimeout) di un minuto. Per configurare questo limite, vedere Chiamare le funzioni JavaScript dai metodi .NET in ASP.NET Core Blazor.
- È possibile fornire un token di annullamento per controllare l'annullamento in base a ogni chiamata. Basarsi sul timeout di chiamata predefinito, se possibile e associato a tempo qualsiasi chiamata al client, se viene fornito un token di annullamento.
- 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:
- Eseguire il wrapping JS delle chiamate di interoperabilità all'interno
try-catch
di istruzioni per tenere conto degli errori che possono verificarsi durante le chiamate. Per altre informazioni, vedere Gestire gli errori nelle app ASP.NET CoreBlazor. - 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 DotNetObjectReference oggetti creati originariamente tramite inserimento delle dipendenze , gli oggetti devono essere registrati come oggetti con ambito. Questo vale per qualsiasi servizio di inserimento delle dipendenze usato dall'app.
- Per i metodi statici, evitare di stabilire lo stato che non può essere limitato al client, a meno che l'app non condivida in modo esplicito lo stato in base alla progettazione in 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 disabilitareeval
e altre primitive JavaScript non sicure. Per altre informazioni, vedere Applicare criteri di sicurezza del contenuto per ASP.NET Core Blazor.
- Convalidare l'input.
- Evitare di implementare l'invio personalizzato delle chiamate .NET oltre all'implementazione dell'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 tutti i dati da inviare 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 dipende dallo stato di visualizzazione di cui è stato eseguito il rendering corrente.
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 if (count < 3) { ... }
controllo all'interno del gestore, la decisione di incrementare 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 da più dispatch
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 su isLoading
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ù dispatches , è consigliabile usare un CancellationToken per annullare le operazioni a esecuzione prolungata quando il componente viene eliminato. 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
- Proteggere le informazioni in transito con HTTPS
- Scripting intersito (XSS)
- Protezione tra le origini
- Click-jacking
- Aprire i reindirizzamenti
Registrazione e dati sensibili
JS le interazioni di interoperabilità tra il client e il server vengono registrate nei log del server con ILogger istanze. Blazor evita di registrare informazioni riservate, ad esempio eventi effettivi o JS input di interoperabilità e output.
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.
Scripting intersito (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.
- Completamento del rendering di dispatch non valido o negativo.
- 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.
- Timeout di qualsiasi chiamata .NET a JavaScript dopo un minuto senza ricevere una risposta dal client. Configurato con CircuitOptions.JSInteropDefaultCallTimeout.
- Esegue la convalida di base su tutti gli input provenienti dal browser durante JS l'interoperabilità:
- I riferimenti .NET sono validi e del tipo previsto dal metodo .NET.
- I dati non sono in formato non valido.
- 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:
- Ignorare i dati e restituire. Ciò consente all'app di continuare l'elaborazione delle richieste.
- Se l'app determina che l'input è non valido e non può essere prodotto dal client legittimo, generare un'eccezione. La generazione di un'eccezione rimuove 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 considerare attendibile l'input sulle JS chiamate di interoperabilità in entrambe le direzioni tra i metodi JavaScript e .NET.
- 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 tramite una sequenza di istruzioni JavaScript (o serializzata in HTML nel caso della pre-gestione):
- 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 la pre-distribuzione, l'output è codificato in HTML, che visualizza anche 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.
Per altre informazioni, vedere Prevent Cross-Site Scripting (XSS) in ASP.NET Core.
Protezione tra le origini
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 aggiungendo i DisableCorsAttribute metadati ai metadati dell'endpoint BlazorSignalR 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.
Click-jacking
Il click-jacking comporta il rendering di un sito come all'interno di <iframe>
un sito da un'origine diversa per ingannare l'utente a eseguire 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 ulteriori informazioni, vedi le seguenti risorse:
- Applicare criteri di sicurezza del contenuto per ASP.NET Core Blazor
- Documentazione Web MDN: X-Frame-Options
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 fa in modo che l'app usi un input utente come parte della chiamata del NavigationManager.NavigateTo metodo.
Questo consiglio si applica anche durante 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 al client di allocare una quantità di memoria non associato.
- Dati all'interno del componente.
- DotNetObjectReference oggetti restituiti al client.
- Proteggere da più dispatch.
- 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 e convalidare l'input dell'utente per gli URL rispetto a NavigationManager.NavigateTo un set di origini consentite, se inevitabile.
- 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.
- È 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.