SQL injection: cos’è e come prevenirlo

Una delle tecniche maggiormante utilizzate negli ultimi anni, che può portare a conseguenze a dir poco devastanti, è l’SQL injection. Gli unici siti che soffrono tale tipologia di attacco sono quelli dinamici, ovvero contenenti scrip lato server (PHP, ASP, JSP, ecc.) per la gestione delle informazioni e per l’inoltro delle interrogazioni al DBMS (Oracle, MySQL, SQLserver e molti altri).

L’SQL injection basa il suo funzionamento sulla costruzione di query “anomale” che se non opportunamente filtrate consentono all’utente malevolo di ottenere i privilegi di amministratore, oppure di accedere al sito senza possedere le credenziali necessarie per il login, o ancora di alterare il contenuto del database ed in alcuni casi del sito stesso (defacing), fino ad arrivare all’hacking della macchina su cui è in esecuzione il DBMS.

Ma facciamo un esempio pratico. Supponiamo di collegarci ad un sito in cui è presente un pannello di gestione dedicato all’admin. A tale pannello ci si può accedere inserendo username e password opportuni. Qui entra in gioco l’SQL injection: attraverso delle stringhe costruite ad hoc posso indurre in errore il sistema di autenticazione, ottenendo l’accesso abusivo alla pagina di amministrazione. Una stringa che potrei inserire nel campo username è la seguente:

'

Si, avete letto bene. Si tratta semplicemente di un apice, il quale viene utilizzato per delimitare il nome della variabile passata al server (ovvero il nome utente). E la password? Non ci serve, poichè se lo scrip ed il DBMS sono vulnerabili avremo già ottenuto l’accesso al pannello di amministrazione. Nel caso in cui tale stringa non produca i risultati sperati si potrebbe usare come username e come password = .

Un altro tipo di stringa usata frequentemente nell’ambito di questo attacco è la seguente:

' OR 'x' = 'x

da inserire sempre nel campo username. Con il primo apice non facciamo altro che delimitare il nome della (presunta) variabile passata al server, mentre con ‘x’ = ‘x indico una condizione sempre vera (non ho inserito appositamente l’ultimo apice in quanto viene aggiunto automaticamente dal DBMS all’interno dell’interrogazione). Ma il vero punto di forza di tale stringa sta nell’OR: tale operatore logico fa in modo che nel caso in cui non venga rispettata la prima condizione, si passi direttamente alla seconda (sempre vera), ottenendo l’accesso.

Un’altra query interessante è la seguente:

' OR 0=0 --

In questo caso non è stato necessario inserire lo 0 tra due apici in quanto non si tratta di una stringa ma di un valore numerico. Per il resto la sintassi è identica a quella dell’interrogazione precedentemente esaminata, eccezion fatta per i due trattini posti alla fine, ovvero . Questi due trattini hanno come scopo quello di portare il DBMS ad ignorare tutto ciò che è presente dopo la seguente istruzione. 

Inoltre, è necessario fare attenzione alle cosiddette query multiple (intervallate dal ;). Eccone un esempio:

 1; DROP TABLE users

In questo modo si riuscirà a cancellare la tabella “users”, in quanto il DBMS interpreterà tale stringa come:

SELECT * FROM DATA WHERE id=1;DROP TABLE users;

Ovviamente le query malevole che possono essere “iniettate” al DBMS sono tantissime, cercate un pò sul Web e ne troverete a migliaia.

Arrivati a questo punto credo sia necessario accennare ad una particolare variante di SQL injection, cioè il blind SQL injection. Questo attacco viene perpetrato contro i database di cui non si conosce la struttura (ad esempio il nome delle tabelle oppure i campi relativi ad esse), e sfrutta gli eventuali messaggi di debug che manda in output il server nel momento in cui viene riscontrata la presenza di un qualche tipo di errore. Basta quindi creare le condizioni adatte affinchè si manifesti l’errore (usando query malformed) per capire qual è la “fisionomia” della base di dati oggetto del nostro attacco. Ecco un esempio:

Obiettivo: Trovare il nome della tabella e della prima colonna
Comando: ‘ having 0=0–
Risultato: Column ‘members.UserID’ is invalid in the select list because it is not contained in an aggregate function and there is no GROUP BY clause.

Obiettivo: Trovare il nome della colonna successiva
Comando: ‘ group by members.UserID having 0=0–
Risultato: Column ‘members.Password’ is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

Obiettivo: Estrarre i nomi di tutte le colonne successive
Comando: ‘ group by members.UserID, members.Password having 0=0 —
Risultato: Column ‘members.FirstName’ is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

Possiamo ripetere questo attacco andando ad inserire il nome della tabella visualizzato nel messaggio di errore immediatamente precedente, fino a quando il server non invierà più notifiche di questo tipo. A questo punto il gioco è fatto: la struttura del database non ha più segreti 🙂

Ah quasi dimenticavo… per MS SQLserver esiste un comando, ovvero sp-password, il quale fa in modo che la query malformed non venga salvata all’interno del file di log. Inoltre, questo server fa ampio uso di Transact SQL (altrimenti conosciuto con l’acronimo T-SQL), che è il “dialetto” mediante al quale vengono costruite moltissime interrogazioni malevole. Per questi (ed altri) motivi, a mio avviso SQLserver è uno dei DBMS più vulnerabili in circolazione.

A questo punto credo si possa parlare dei metodi grazie ai quali è possibile prevenire (o per lo meno limitare) gli effetti di un attacco di questo genere. Per prima cosa occorre scegliere un DBMS poco vulnerabile (ad esempio MySQL). Dopodichè è necessario prestare molta attenzione (a livello di scrip) alla cosiddetta validazione dell’input. Se ad esempio il server si aspetta un numero, è necessario controllare che tale variabile sia effettivamente di tipo numerico. Inoltre si deve evitare che all’interno della query vengano inseriti i cosiddetti caratteri speciali, quali , , #, ecc. , che potrebbero mandare il DBMS “in confusione”. A tal scopo esistono alcune funzioni che i linguaggi di scripting, quali PHP, ci mettono a disposizione. Una di queste è mysql_real_escape_string(), ed è utilizzabile quando ad interfacciarsi con il nostro scrip è un server MySQL. Essa non fa altro che aggiungere automaticamente un carattere di “escape” (ovvero il backslash) davanti ad alcuni caratteri, quali backslah x00, backslash n, backslash “ e così via. In tal modo si rende “immune” all’SQL injection l’argomento da passare alla funzione mysql_query() (che invierà l’interrogazione vera e propria).

Un’altra funzione che può tornare utile è stripslashes(). Essa aggiunge un escape davanti a tutti i , , e Null. Si potrebbe evitare di usarla semplicemente andando ad impostare correttamente il file di configurazione di PHP, cioè php.ini: basta abilitare l’opzione magic_quotes_gpc (dove gpc sta per GET, POST E Cookie).

Si potrebbe anche (in teoria) eliminare a priori gli apici (anche se questa soluzione è molto limitativa), oppure li si potrebbe raddoppiare. Si potrebbe anche effettuare un controllo delle stringhe passate al DBMS attraverso delle espressioni regolari, altrimenti dette Regex. Un’altra valida soluzione consiste nell’usare una whitelist, ovvero un insieme di stringhe ammissibili e considerate non malevole. Inoltre, per evitare il blind SQL injection, si potrebbero disabilitare i messaggi di debug (sempre via php.ini) oppure utilizzare opportunamente l’operatore di silence (@) messo a disposizione da PHP. Per quanto riguarda le query multiple, invece, conviene sempre disabilitarle (per ovvie ragioni di sicurezza).

Ricordatevi comunque di tenere sempre aggiornato il DBMS ed il server, installando le eventuali patch, e controllate che il sistema di gestione del database non abbia privilegi elevati, in quanto un hacker, ottenendone il controllo, potrebbe compromettere la sicurezza dell’intera macchina. 

Concludo questo post (redatto a titolo informativo) mettendovi in guardia sul fatto che il solo TENTATIVO di accesso abusivo ad un sito (oppure ad un sistema telematico in genere) è considerato reato penale. Quindi se proprio volete fare dei test, fateli sui vostri server per saggiarne la robustezza. Come si dice… uomo avvisato mezzo salvato :). A presto.

SQL injection: cos’è e come prevenirloultima modifica: 2009-01-27T10:54:06+01:00da nazarenolatella
Reposta per primo quest’articolo

Lascia un commento