Input e output
Il punto debole più comune nelle applicazioni attuali, a livello di sicurezza, è la non corretta elaborazione dei dati ricevuti da origini esterne, in particolare l'input dell'utente. È importante esaminare sempre attentamente qualsiasi input per assicurarsi che sia stato convalidato prima dell'uso. Se non si analizza l'input dell'utente per individuare possibili attacchi, le conseguenze potrebbero essere l'esposizione o la perdita di dati, l'elevazione dei privilegi o persino l'esecuzione di codice dannoso nei computer di altri utenti.
L'aspetto tragico della situazione è che questo scenario è un problema semplice da risolvere. In questa unità descriveremo come trattare i dati quando vengono ricevuti, quando vengono visualizzati sullo schermo e quando vengono archiviati per un uso futuro.
Perché è necessario convalidare l'input?
Immaginiamo di voler compilare un'interfaccia che consenta a un utente di creare un account in un sito Web. I dati del profilo includono un nome, un indirizzo di posta elettronica e un nome alternativo che saranno visibili a chiunque visiti il sito. Supponiamo che un nuovo utente crei un profilo e immetta un nome alternativo che include alcuni comandi SQL. Ad esempio, cosa accade se un utente malintenzionato immette un input come l'estratto seguente:
Eve'); DROP TABLE Users;--
Se si inserisse ciecamente questo valore in un database, potrebbe alterare l'istruzione SQL in modo da eseguire comandi potenzialmente dannosi. Questo esempio è noto come "attacco SQL injection" ed è uno dei numerosi tipi di exploit possibili quando non si gestiscono correttamente gli input. Come si può risolvere questa situazione? In questa unità verrà illustrato quando convalidare l'input, come codificare l'output e creare query con parametri, risolvendo l'exploit descritto sopra. Queste sono le tre principali tecniche di difesa dall'immissione di input dannosi nelle applicazioni.
Quando è necessario convalidare l'input?
La risposta è sempre. Occorre convalidare ogni input per l'applicazione. Sono inclusi i parametri nell'URL, l'input dell'utente, i dati del database, i dati di un'API e qualsiasi elemento passato in formato non crittografato che potrebbe essere modificato da un utente. Usare sempre l'approccio con elenco di elementi consentiti, che prevede l'accettazione solo di input notoriamente valido, invece di un elenco di elementi bloccati (un approccio che prevede la ricerca specifica di input non valido), in quanto è impossibile avere un elenco completo di input potenzialmente pericolosi. Eseguire queste operazioni sul lato server, piuttosto che sul lato client, o idealmente su entrambi i lati, per garantire che le misure di sicurezza non possano essere eluse. Considerare TUTTI i dati come non attendibili per proteggersi dalle più comuni vulnerabilità per le app Web.
Se si usa ASP.NET, il framework offre un ottimo supporto per la convalida dell'input sia sul lato client che sul lato server.
Se si usa un altro framework Web, è possibile consultare alcune ottime tecniche di convalida dell'input disponibili in Input Validation Cheatsheet di OWASP.
Usare sempre query con parametri
I database SQL sono comunemente usati per archiviare i dati. Ad esempio, l'applicazione potrebbe archiviare le informazioni sui profili utente in un database. È consigliabile evitare di creare SQL inline o altre query di database nel codice usando input utente non elaborato e di inviare il codice direttamente al database. Come evidenziato in precedenza, tale pratica può causare gravi rischi per la sicurezza.
Ad esempio, non creare codice come il seguente esempio di SQL inline:
string userName = Request.QueryString["username"]; // receive input from the user BEWARE!
...
string query = "SELECT * FROM [dbo].[users] WHERE userName = '" + userName + "'";
In questo esempio vengono concatenate più stringhe di testo per creare la query, recuperando l'input dall'utente e generando una query SQL dinamica per cercare l'utente. Anche in questo caso, se un utente malintenzionato capisse quale azione si sta eseguendo o anche solo provasse diversi stili di input per rilevare eventuali vulnerabilità, le conseguenze potrebbero essere estremamente gravi. Usare invece istruzioni SQL con parametri o stored procedure, come illustrato di seguito:
-- Lookup a user
CREATE PROCEDURE sp_findUser
(
@UserName varchar(50)
)
SELECT * FROM [dbo].[users] WHERE userName = @UserName
Con questo metodo, è possibile richiamare la stored procedure dal codice in maniera sicura, passandole la stringa userName
senza rischi che sia considerata parte dell'istruzione SQL.
Codificare sempre l'output
Qualsiasi output presentato visivamente o all'interno di un documento deve sempre essere codificato e preceduto da un carattere di escape. In questo modo l'utente è possibile proteggersi nel caso in cui qualcosa sia stato tralasciato nel processo di bonifica o nel caso in cui il codice generi accidentalmente elementi che possono essere usati in modo dannoso. Questo principio di progettazione assicurerà che tutti gli elementi vengano visualizzati come output e non vengano inavvertitamente interpretati come elementi che devono essere eseguiti, un'altra tecnica di attacco comune detta "XSS (Cross-Site Scripting").
Poiché la prevenzione di attacchi XSS è un requisito comune per le applicazioni, questa tecnica di sicurezza è un'altra area gestita automaticamente da ASP.NET. Per impostazione predefinita, tutto l'output è già codificato. Se si usa un altro framework Web, è possibile verificare le opzioni impostate per la codifica dell'output nei siti Web con XSS Prevention Cheatsheet di OWASP.
Riepilogo
La purificazione e la convalida dell'input sono requisiti necessari per assicurarsi che l'input sia valido e possa essere usato e archiviato in tutta sicurezza. La maggior parte dei framework Web più moderni offre funzionalità predefinite che consentono di automatizzare parte di queste operazioni. È possibile controllare la documentazione del framework preferito per scoprire le funzionalità offerte. Sebbene le applicazioni Web siano più a rischio, tenere presente che altri tipi di applicazioni possono essere altrettanto vulnerabili. Non pensare di essere al sicuro solo perché la nuova applicazione è un'app desktop. Sarà comunque necessario gestire correttamente l'input dell'utente per assicurare che nessuno possa usare l'app per danneggiare i dati o, peggio ancora, la reputazione dell'azienda.