SQL è l'acronimo di Structured Query Language. Una interrogazione SQL può essere eseguita con vari comandi: SELECT, UPDATE o INSERT.
Le query che si possono formare con SELECT possono specificare un criterio che i dati da prelevare devono rispettare. Per esempio:
SELECT * FROM Utenti WHERE userName = 'donDiego';
La query precedente specifica, con la clausola WHERE userName = 'donDiego', che i dati che si vogliono prelevare dalla tabella Utenti devono soddisfare la condizione che il campo userName contenga il valore donDiego.
Questo esempio di interrogazione mostra che il linguaggio SQL è molto semplice da imparare e, con esso, si possono costruire facilmente delle interrogazioni del data base. Ma, allo stesso tempo, il linguaggio consente ad un utente malintenzionato di violare la riservatezza delle informazioni.
Un attacco SQL injection inietta o manipola il comando SQL. Con l'aggiunta di un comando SQL a una query, si riesce a manomettere un database in modi inaspettati.
Uno dei modi più diffusi per autenticare un utente che intende accedere ad un'area riservata di un sito web consiste nel fornirgli un form con due caselle di testo in cui deve inserire il nome Utente e la password. Si abbia il seguente form:
<form name="frmLogin" action="login.php" method="post"> Nome Utente: <input type="text" name="userName" /> <br /> Password: <input type="text" name="password" /> <br /> <input type="submit" value ="login"/> <br /> </form>Che si presenta in questo modo:
Quando si preme il pulsante submit per inviare la richiesta i valori scritti nelle caselle username e password vengono consegnati allo script login.php, nell'array associativo $_POST.
Tramite una query è molto semplice convalidare i dati forniti dall'utente: basta interrogare il data base e accertarsi che quell'utente esista. Lo script login.php potrebbe essere il seguente:
<?php mysql_connect("localhost", "root", ""); mysql_select_db("Utenti"); $userName = $_POST['userName']; $password = $_POST['password']; $sql = "SELECT * FROM users WHERE username = '".$userName."' AND password = '".$password."'"; $result = mysql_query( $sql ) or die ( 'interrogazione del database fallita.'.mysql_error() ); if (mysql_fetch_array($result)) { echo "Utente riconosciuto"; } else { echo "Utente non riconosciuto"; } ?>
Il procedimento di autenticazione, usando l'esempio appena mostrato, consiste nel proporre all'utente il modulo di autenticazione, in cui l'utente inserisce il nome utente e la password. premendo il pulsante "Submit" l'utente riceve la risposta "Utente riconosciuto" se esiste un record nel data base che possiede gli stessi valori, altrimenti riceve la risposta: "Utente non riconosciuto" se non esiste nessun record con i valori forniti.
Si crei, con mySQL Console, un database Utenti su cui svolgere gli esempi. Poi si crei al suo interno una tabella users contenente i campi userName e password.
CREATE DATABASE Utenti; USE Utenti; CREATE TABLE Utenti ( IDutente int not null auto_increment PRIMARY KEY, userName varchar(20), password varchar(60) ); insert into users(userName, password) values('donDiego', 'Zorro'); insert into users(userName, password) values('admin', 'abcdef'); insert into users(userName, password) values('utente', 'password');
Se si apre la pagina web che propone il form di immissione delle credenziali, e si scrive donDiego nel campo "nome Utente" e Zorro nel campo "password" si riceve la risposta "Utente Riconosciuto".
La pagina login.php, leggendo i parametri ricevuti, forma la seguente query:
SELECT * FROM users WHERE username = 'donDiego' AND password = 'Zorro'
Ma si provi a introdurre "donDiego" nel campo Nome Utente e i caratteri ' or 1=1 -- [spazio] nel campo password:
La query risultante è:
SELECT * FROM users WHERE username = 'donDiego' AND password = '' or 1=1 -- '
Adesso la query cerca un record con il campo username uguale a donDiego a condizione che il campo password sia vuoto oppure che valga l'uguaglianza 1=1.
Il significato dei caratteri immessi nel campo password è il seguente:
l'apice ha lo scopo di chiudere l'apice che delimita la stringa password,
la condizione 1=1 forza a true il risultato dell'espressione logica,
i due segni meno seguiti da uno spazio servono a commentare il resto della linea, in modo che non venga restituito il messaggio di errore per la presenza dell'altro apice che delimita la stringa password.
Quindi se lo script login.php restituisce una linea (perchè si conosce un nome utente) si riesce ad accedere ad un'area riservata senza conoscere la password.
Un altro modo, molto diffuso, di verificare l'autenticità di un utente consiste nel recuperare il nome utente registrato nel data base, come nel seguente esempio:
<?php mysql_connect("localhost", "root", ""); mysql_select_db("Utenti"); $userName = $_POST['userName']; $password = $_POST['password']; $sql = "SELECT username FROM users WHERE username = '".$userName."' AND password = '".$password."'"; $result = mysql_query( $sql ) or die ( 'interrogazione del database fallita.'.mysql_error() ); if ($record=mysql_fetch_array($result)) { echo "benvenuto ".$record['username']; } else { echo "Utente non riconosciuto"; } ?>
Si provi adesso con il campo "nome Utente", introducendo i seguenti valori:
Quando si preme il pulsante "Submit" per inviare i dati alla pagina login.php si forma la seguente query:
SELECT * FROM users WHERE username = '' or 1=1 -- ' AND password = ''
L'interrogazione precedente restituisce tutti i record della tabella users e, con il controllo che viene effettuato sul risultato, l'utente viene riconosciuto.
Gli esempi chiariscono il significato del termine attacco per SQL injection: si aggiunge un codice che manipola la query per ottenere risultati diversi da quelli aspettati dal programma.
La pagina di login restituisce Benvenuto donDiego perchè è il primo utente che è stato inserito nella tabella.
Si forzi un errore nella query di interrogazione del database, inserendo (con union) nel campo username una seconda query:
Dopo aver premuto il pulsante submit, il sistema risponde con il messaggio di errore:
interrogazione del database fallita: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'from' AND password = ''' at line 1
Il programma ha rivelato all'utente non autorizzato il nome di un campo della tabella. A questo punto di si potrebbe autenticare anche inserendo i seguenti campi:
Il sistema fornisce il messaggio di benvenuto rivelando il valore del campo username del primo utente trovato nel database che ha scelto una password avente la lettera f come primo carattere.
Se si completa il form di immissione dei campi con i seguenti valori:
Il sistema risponde con un messaggio di errore che rivela il nome del database:
interrogazione del database fallita: Table 'utenti.tabella' doesn't exist
Si scopre che il nome del data base è utenti.
Sfida il database di esempio