Condividi tramite


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

Questo articolo illustra le considerazioni sulla sicurezza che gli sviluppatori devono tenere in considerazione durante lo sviluppo Blazor di App Web con il rendering statico sul lato server.

Blazor combina tre modelli diversi in uno per la scrittura di app Web interattive. Rendering lato server tradizionale, ovvero un modello di richiesta/risposta basato su HTTP. Rendering lato server interattivo, ovvero un modello di rendering basato su SignalR. Infine, il rendering lato client, ovvero un modello di rendering basato su WebAssembly.

Tutte le considerazioni generali sulla sicurezza definite per le modalità di rendering interattive si applicano a Blazor App Web quando sono presenti componenti interattivi per il rendering in una delle modalità di rendering supportate. Le sezioni seguenti illustrano le considerazioni sulla sicurezza specifiche per il rendering lato server non interattivo in Blazor App Web e gli aspetti specifici che si applicano quando le modalità di rendering interagiscono tra loro.

Considerazioni generali sul rendering lato server

Il modello di rendering lato server (SSR) si basa sul modello tradizionale di richiesta/risposta di HTTP. Di conseguenza, esistono aree comuni di preoccupazione tra SSR e HTTP di richiesta/risposta. Le considerazioni generali sulla sicurezza e le minacce specifiche devono essere attenuate correttamente. Il framework fornisce meccanismi predefiniti per la gestione di alcune di queste minacce, ma altre minacce sono specifiche del codice dell'app e devono essere gestite dall'app. Queste minacce possono essere classificate come segue:

  • Autenticazione e autorizzazione: l'app deve assicurarsi che l'utente sia autenticato e autorizzato ad accedere all'app e alle risorse esposte. Il framework fornisce meccanismi predefiniti per l'autenticazione e l'autorizzazione, ma l'app deve garantire che i meccanismi siano configurati e usati correttamente. I meccanismi predefiniti per l'autenticazione e l'autorizzazione sono trattati nel Blazor nodo Sicurezza server della documentazione e nel nodo Sicurezza e Identity nodo della documentazione di ASP.NET Core, quindi non verranno trattati qui.

  • Convalida e purificazione dell'input: tutti gli input provenienti da un client devono essere convalidati e sanificati prima dell'uso. In caso contrario, l'app potrebbe essere esposta ad attacchi, ad esempio SQL injection, scripting tra siti, richiesta intersito falsa, reindirizzamento aperto e altre forme di attacchi. L'input può provenire da qualsiasi punto della richiesta.

  • Gestione delle sessioni: la gestione corretta delle sessioni utente è fondamentale per garantire che l'app non sia esposta agli attacchi, ad esempio correzioni di sessione, hijack della sessione e altri attacchi. Le informazioni archiviate nella sessione devono essere protette e crittografate correttamente e il codice dell'app deve impedire a un utente malintenzionato di indovinare o modificare le sessioni.

  • Gestione e registrazione degli errori: l'app deve assicurarsi che gli errori vengano gestiti e registrati correttamente. In caso contrario, l'app potrebbe essere esposta ad attacchi, ad esempio la divulgazione di informazioni. Ciò può verificarsi quando l'app restituisce informazioni riservate nella risposta o quando l'app restituisce messaggi di errore dettagliati con dati che possono essere usati per attaccare l'app.

  • Protezione dei dati: i dati sensibili devono essere protetti correttamente, che include la logica dell'app durante l'esecuzione in WebAssembly, perché può essere facilmente invertita.

  • Denial of Service: l'app deve assicurarsi che non sia esposta ad attacchi, ad esempio Denial of Service. Ciò si verifica, ad esempio, quando l'app non è protetta correttamente dagli attacchi di forza bruta o quando un'azione può causare l'uso di troppe risorse dell'app.

Convalida e purificazione dell'input

Tutti gli input provenienti dal client devono essere considerati non attendibili, a meno che le relative informazioni non siano state generate e protette nel server, ad esempio un token CSRF, un'autenticazione cookie, un identificatore di sessione o qualsiasi altro payload protetto con la crittografia autenticata.

L'input è in genere disponibile per l'app tramite un processo di associazione, ad esempio tramite l'attributo o[SupplyParameterFromForm] l'attributo[SupplyParameterFromQuery]. Prima di elaborare questo input, l'app deve assicurarsi che i dati siano validi. Ad esempio, l'app deve verificare che non siano presenti errori di associazione durante il mapping dei dati del modulo a una proprietà del componente. In caso contrario, l'app potrebbe elaborare dati non validi.

Se l'input viene usato per eseguire un reindirizzamento, l'app deve assicurarsi che l'input sia valido e che non punti a un dominio considerato non valido o a un sottopercorso non valido all'interno del percorso di base dell'app. In caso contrario, l'app può essere esposta agli attacchi di reindirizzamento aperti, in cui un utente malintenzionato può creare un collegamento che reindirizza l'utente a un sito dannoso.

Se l'input viene usato per eseguire una query di database, l'app deve confermare che l'input è valido e che non espone l'app agli attacchi SQL injection. In caso contrario, un utente malintenzionato potrebbe essere in grado di creare una query dannosa che può essere usata per estrarre informazioni dal database o per modificare il database.

Anche i dati che potrebbero provenire dall'input dell'utente devono essere sanificati prima di essere inclusi in una risposta. Ad esempio, l'input potrebbe contenere CODICE HTML o JavaScript che può essere usato per eseguire attacchi di scripting tra siti, che possono essere usati per estrarre informazioni dall'utente o per eseguire azioni per conto dell'utente.

Il framework fornisce i meccanismi seguenti per facilitare la convalida e la purificazione dell'input:

  • Tutti i dati del modulo associati vengono convalidati per la correttezza di base. Se non è possibile analizzare un input, il processo di associazione segnala un errore che l'app può individuare prima di eseguire qualsiasi azione con i dati. Il componente predefinito EditForm tiene conto di questo valore prima di richiamare il callback del OnValidSubmit modulo. Blazor evita l'esecuzione del callback se sono presenti uno o più errori di associazione.
  • Il framework usa un token antiforgery per proteggersi da attacchi falsi di richiesta intersito. Per altre informazioni, vedere ASP.NET Blazor Panoramica dell'autenticazione e dell'autorizzazione e dei moduli di base di ASP.NET CoreBlazor.

Tutte le autorizzazioni e di input devono essere convalidate nel server al momento dell'esecuzione di una determinata azione per garantire che i dati siano validi e accurati in quel momento e che l'utente sia autorizzato a eseguire l'azione. Questo approccio è coerente con le indicazioni sulla sicurezza fornite per il rendering lato server interattivo.

Gestione della sessione

La gestione delle sessioni viene gestita dal framework. Il framework usa una sessione cookie per identificare la sessione utente. La sessione cookie è protetta usando le API di protezione dei dati di base ASP.NET. La sessione cookie non è accessibile al codice JavaScript in esecuzione nel browser e non può essere facilmente indovinata o manipolata da un utente.

Per quanto riguarda altri dati di sessione, ad esempio i dati archiviati all'interno dei servizi, i dati di sessione devono essere archiviati all'interno di servizi con ambito, in quanto i servizi con ambito sono univoci per una determinata sessione utente, anziché i servizi singleton condivisi tra tutte le sessioni utente in una determinata istanza del processo.

Quando si tratta di SSR, non c'è molta differenza tra i servizi con ambito e temporanei nella maggior parte dei casi, poiché la durata del servizio è limitata a una singola richiesta. Esistono differenze in due scenari:

  • Se il servizio viene inserito in più posizioni o in momenti diversi durante la richiesta.
  • Se il servizio può essere usato in un contesto di server interattivo, in cui sopravvive a più rendering e al suo fondamentale ambito per la sessione utente.

Registrazione e gestione degli errori

Il framework fornisce la registrazione predefinita per l'app a livello di framework. Il framework registra eventi importanti, ad esempio quando il token antiforgery per un modulo non riesce a convalidare, quando viene avviato il rendering di un componente radice e quando viene inviata un'azione. L'app è responsabile della registrazione di qualsiasi altro evento che potrebbe essere importante da registrare.

Il framework fornisce la gestione degli errori predefinita per l'app a livello di framework. Il framework gestisce gli errori che si verificano durante il rendering di un componente e usa il meccanismo di limite degli errori per visualizzare un messaggio di errore descrittivo o consente all'errore di passare al middleware di gestione delle eccezioni, configurato per il rendering della pagina di errore.

Gli errori che si verificano durante il rendering del flusso dopo l'invio della risposta al client vengono visualizzati nella risposta finale come messaggio di errore generico. I dettagli sulla causa dell'errore vengono inclusi solo durante lo sviluppo.

Protezione dei dati

Il framework offre meccanismi per proteggere le informazioni riservate per una determinata sessione utente e garantisce che i componenti predefiniti usino questi meccanismi per proteggere le informazioni riservate, ad esempio la protezione dell'identità utente quando si usa cookie l'autenticazione. Al di fuori degli scenari gestiti dal framework, il codice per sviluppatori è responsabile della protezione di altre informazioni specifiche dell'app. Il modo più comune per eseguire questa operazione consiste nell'usare le API di protezione dei dati di base ASP.NET o qualsiasi altra forma di crittografia. Come regola generale, l'app è responsabile di:

  • Assicurarsi che un utente non possa esaminare o modificare le informazioni private di un altro utente.
  • Assicurarsi che un utente non possa modificare i dati utente di un altro utente, ad esempio un identificatore interno.

Per quanto riguarda la protezione dei dati, è necessario comprendere chiaramente dove viene eseguito il codice. Per il rendering statico lato server (SSR statico) e il rendering interattivo lato server (SSR interattivo), il codice viene archiviato nel server e non raggiunge mai il client. Per la modalità di rendering Interactive WebAssembly, il codice dell'app raggiunge sempre il client, il che significa che tutte le informazioni riservate archiviate nel codice dell'app sono disponibili per chiunque abbia accesso all'app. L'offuscamento e altre tecniche simili a "proteggere" il codice non è efficace. Quando il codice raggiunge il client, può essere invertito per estrarre le informazioni riservate.

Denial of Service

A livello di server, il framework fornisce limiti ai parametri di richiesta/risposta, ad esempio le dimensioni massime della richiesta e le dimensioni dell'intestazione. Per quanto riguarda il codice dell'app, Blazoril sistema di mapping dei moduli definisce limiti simili a quelli definiti dal sistema di associazione di modelli di MVC:

  • Limite al numero massimo di errori.
  • Limite alla profondità massima di ricorsione per il binder.
  • Limite al numero massimo di elementi associati in una raccolta.

Sono inoltre previsti limiti definiti per il modulo, ad esempio le dimensioni massime della chiave del modulo e le dimensioni del valore e il numero massimo di voci.

In generale, l'app deve valutare quando è possibile che una richiesta attivi una quantità asimmetrica di lavoro da parte del server. Ad esempio, quando l'utente invia una richiesta con parametri da N e il server esegue un'operazione in risposta che è N volte più costosa, dove N è un parametro che un utente controlla e può crescere indefinitamente. In genere, l'app deve imporre un limite alla N massima che sia disposta a elaborare o assicurarsi che qualsiasi operazione sia minore, uguale o più costosa rispetto alla richiesta da un fattore costante.

Questo aspetto ha più a che fare con la differenza di crescita tra il lavoro eseguito dal client e il lavoro eseguito dal server rispetto a un confronto 1→N specifico. Ad esempio, un client potrebbe inviare un elemento di lavoro (inserendo elementi in un elenco) che richiede N unità di tempo per l'esecuzione, ma il server necessita di N^2^ per l'elaborazione (perché potrebbe eseguire un'operazione molto ingenua). È la differenza tra N e N^2^ che conta.

Di conseguenza, esiste un limite alla quantità di lavoro che il server deve essere disposto a eseguire, che è specifico per l'app. Questo aspetto si applica ai carichi di lavoro lato server, poiché le risorse si trovano nel server, ma non si applicano necessariamente ai carichi di lavoro WebAssembly nel client nella maggior parte dei casi.

L'altro aspetto importante è che questo non è riservato solo al tempo della CPU. Si applica anche a qualsiasi risorsa, ad esempio memoria, rete e spazio su disco.

Per i carichi di lavoro WebAssembly, in genere la quantità di lavoro eseguita dal client è scarsa, poiché il client è in genere limitato dalle risorse disponibili nel client. Tuttavia, esistono alcuni scenari in cui il client potrebbe essere interessato, se ad esempio un'app visualizza i dati di altri utenti e un utente è in grado di aggiungere dati al sistema che forza i client che visualizzano i dati per eseguire una quantità di lavoro che non è proporzionale alla quantità di dati aggiunti dall'utente.

  • Assicurarsi che l'utente sia autenticato e autorizzato ad accedere all'app e alle risorse esposte.
  • Convalidare e purificare tutti gli input provenienti da un client prima di usarlo.
  • Gestire correttamente le sessioni utente per assicurarsi che lo stato non venga erroneamente condiviso tra gli utenti.
  • Gestire e registrare correttamente gli errori per evitare di esporre informazioni riservate.
  • Registrare eventi importanti nell'app per identificare i potenziali problemi e le azioni di controllo eseguite dagli utenti.
  • Proteggere le informazioni riservate usando le API di protezione dei dati di base ASP.NET o uno dei componenti disponibili (Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage, PersistentComponentState).
  • Assicurarsi che l'app comprenda le risorse che possono essere utilizzate da una determinata richiesta e che siano previsti limiti per evitare attacchi Denial of Service.