25 gennaio 2008

SQL injection: le contromisure

Nel post precedente abbiamo visto quanto sia facile attaccare un database mediante una SQL injection, pur avendo scalfito solo la superficie di questa tipologia di attacchi. Adesso vediamo quali sono le contromisure generali da adottare per limitarne l'impatto. Le linee d'azione da seguire sono raggruppabili in due fronti: ridurre le vulnerabilità dell'applicazione e monitorare gli attacchi in corso.


Ridurre le vulnerabilità dell'applicazione

Come già detto, la SQL injection agisce mediante l'applicazione web, e i suoi effetti saranno tanto maggiori quanti più privilegi saranno stati assegnati all'account con cui si connette al database. Analizzando le tecniche usate dagli aggressori, col tempo si sono adottate varie misure per contrastarne gli effetti. Elenco quelle che si sono dimostrate più efficaci:

  • convalidare tutti gli input inseriti nei form, e purgarli di caratteri e stringhe particolari che non dovrebbero farne parte (per esempio gli asterischi, i segni di uguaglianza, i punti e virgola, gli identificativi di commento ecc.);

  • evitare il più possibile le stringhe concatenate per generare i comandi SQL da inviare al database, cercando per quanto possibile di passare i dati di input come parametri, ricorrendo per esempio a prepared statements, parameter collections e parameterized stored procedures (non mi dilungo nelle spiegazioni, per le quali è sufficiente una ricerca su internet);

  • ricorrere a una stored procedure sicura per il login dell'applicazione, evitando l'uso di una query dinamica;

  • usare pacchetti che testano in automatico la vulnerabilità alla SQL injection, come quelli segnalati qui. Anche quelli che effettuano i test più semplici possono tornare utili per individuare falle nell'applicazione;

  • ridurre i privilegi di accesso dell'applicazione. Se questa accede al database per compiti diversi (amministrazione, inserimenti, reporting ecc.) e in contesti diversi (come i diversi dipartimenti o uffici di un'organizzazione), gli sviluppatori dovrebbero rinunciare a un'unica connessione indistinta con ampi privilegi, per ricorrere a più connessioni limitate ad hoc. Se ciò non è possibile (perché magari l'applicazione è già stata completata e non può essere modificata per qualsiasi ragione), chi amministra il database dovrebbe fare in modo di identificare i privilegi minimi comuni a tutti gli utilizzatori dell'applicazione per "blindare" opportunamente la connessione.



Monitorare gli attacchi

Le SQL injection più pericolose non vanno a segno al primo colpo, ma richiedono più prove in successione, nel tentativo di allineare la query inviata con i campi a cui si sta cercando di accedere (in particolare, l'attaccante deve identificare gli attributi e i tipi di dato). Questi tentativi potrebbero essere identificati dall’amministratore del sistema, magari in tempo reale usando appositi tool, dandogli così il tempo di correre ai ripari. L’identificazione può avvenire in vari modi:

  • riconoscendo le “signatures” di un attacco: l’uso di un IDS (Intrusion Detection System) che supporti anche l’individuazione di intrusioni su basi dati può agevolmente intercettare sezioni di stringhe SQL non conformi come le identità, le UNION, o le condizioni WHERE che seguono indicatori di commento (segno di un troncamento deliberato di una query). Questa soluzione non è purtroppo ottimale, sia per la percentuale di falsi positivi (per esempio una UNION potrebbe essere legittima) sia per la vasta casistica di stringhe di injection che bisognerebbe controllare;

  • ricevendo segnali di errore SQL dal DBMS: solitamente un’applicazione entrata in produzione dopo una seria fase di test non genera errori sul numero di attributi di una SELECT, sulla mancata chiusura di apici o sulla conversione di tipo di dato, che rappresentano invece il segnale di allarme di un attacco in atto. Occorre pertanto monitorare costantemente gli errori ritornati dal DBMS. A tale proposito, sarebbe buona norma segnalare gli errori SQL solo al DBA e mai all’utente dell’applicazione (se non genericamente), perché sono fonte di informazioni sullo schema e sul funzionamento del database;

  • confrontando il codice SQL con una “baseline”: poiché l’applicazione ripeterà sempre gli stessi tipi di operazione, e quindi gli stessi comandi SQL, è possibile stilare un elenco di riferimento di queste operazioni - la baseline per l'appunto - con cui confrontare ogni successiva stringa SQL. Se questa si discosta dalla baseline, si genera un allarme. Questo metodo può essere applicato mediante un SQL firewall, che oltre a identificare una probabile injection potrà bloccarla;

  • mediante l’analisi dei log: in quest'ultimo caso l’attacco ha già avuto luogo (con successo o meno), e le operazioni compiute dall’aggressore sono state registrate nei file di log (se non sono stati cancellati per eliminare le tracce), che potranno essere analizzati per ricostruire l'accaduto e intervenire sulle falle sfruttate per l'attacco.


Sul web esiste moltissimo materiale per approfondire l'argomento, che non è certo nuovo e neppure è una tecnica alla portata di pochi (è una delle prime imparate dagli script kiddies). È così sconfortante allora osservare quanto facilmente abbia successo... persino con i siti di tante università che insegnano informatica!

Nessun commento: