Con tale termine intendiamo tutti gli attacchi ad un'applicazione Web - nel nostro caso PHP - che consentano di modificare l'interazione della stessa con il database: nel caso vengano eseguite, lato server, interrogazioni MySQL costruite su quanto ricevuto dal client, senza un controllo sull'input è possibile che un cracker crei, "tecnicamente" parlando, disastri irrimediabili. Per una panoramica generale su queste tecniche si rimanda all'articolo Tecniche: SQL Injection pubblicato nella sezione Sicurezza di HTML.it e Proteggersi dalla SQL Injection pubblicato nella sezione PHP.
Autenticazione
Primo esempio, autenticazione utente
Riporterò ora un primo, classicissimo, esempio.
Posto che la direttiva magic_quotes_gpc del php.ini sia impostata ad OFF e non venga fatto l'escape del carattere " ' ", studiamo il caso in cui l'autenticazione degli utenti di un'ipotetica applicazione Web PHP utilizzi la seguente logica. I dati passati allo script di autenticazione giungono, come al soltio, direttamente da un form HTML.
$utente_autorizzato=0;
$sql="SELECT * FROM tabella_utenti
WHERE usr='".$_POST['username']."' AND pwd='".$_POST['password']."'";
$query=mysql_query($sql,$db);
if (mysql_num_rows($query)>0) $utente_autorizzato=1;
Se username e password inserite lato client sono rispettivamente marco e miapass, la query assume la forma:
SELECT * FROM tabella_utenti WHERE usr='marco' AND pwd='miapass';
A questo punto, se nel database è presente un record che soddisfi a tale query, l'utente è autorizzato ad accedere all'applicazione.
La vulnerabilità è però in agguato: se username e password inserite lato client, ossia direttamente nei moduli di autenticazione, fossero, invece, qualsiasi_nome e qualsiasi_stringa' OR 1 - - (spazio), la query assumerebbe la diabolica forma:
SELECT * FROM tabella_utenti
WHERE usr='qualsiasi_nome' AND pwd='qualsiasi_stringa' OR 1 -- '
"- - " rappresenta il delimitatore di commento: tutto ciò che segue viene ignorato.
Essendo la query sempre soddisfatta (ha valore di verità sempre 1), il suo risultato sarà l'intera lista degli utenti (tutte le entry della tabella) e il cracker entrerà, autenticato, nel programma.
In presenza di una qualsivoglia tipologia di riconoscimento utente, l'identità che assumerà il cracker (intendo il nome utente con cui risulterà collegato) dipende da come è strutturato il codice.
Se il primo utente di tabella_utenti è l'amministratore, molto probabilmente il cracker lo impersonificherà. Spesso infatti, presupponendo il programmatore che solo una sia la riga risultante dall'esito dell'interrogazione SQL, proprio la prima riga del record verrà associata all'utente autenticato (cracker).
Autenticazione utente con inganno sullo username
Abbiamo visto come sia possibile ottenere accesso non autorizzato inserendo stringhe (in)opportune nel campo riservato alla password. Lo stesso si può ottenere anche utilizzando il campo username.
Inserendo in username la stringa: qualsiasi_nome' OR 1 - - (spazio)
Si ottiene:
SELECT * FROM tabella_utenti
WHERE usr='qualsiasi_nome' OR 1 -- ' AND pwd='qualsiasi_stringa';
E l'accesso è assicurato.
Autenticazione con firma sulla password
Poniamo invece subito all'attenzione una questione fondamentale: se (al contrario di come fatto finora) il sistema di autenticazione utilizza un ben più sicuro sistema di firma, per il quale la password non è memorizzata in chiaro su database ed in sua vece è memorizzato il suo hash, il programma sarà non vulnerabile al primo exploit menzionato.
Se infatti confrontiamo l'hash di quanto inserito dall'utente con ciò che è su db (già "hashato"), il comando md5 vanifica, trasparentemente, gli sforzi del cracker.
Se il codice di autenticazione fosse infatti:
$utente_autorizzato=0;
$sql="SELECT * FROM tabella_utenti
WHERE usr='".$_POST['username']."' AND pwd='".md5($_POST['password'])."'";
$query=mysql_query($sql,$db);
if (mysql_num_rows($query) > 0)
{
$utente_autorizzato=1;
}
la query, anche in presenza di tentativi di hacking (sulla password) risulterebbe simile a:
SELECT * FROM tabella_utenti
WHERE usr='qualsiasi_nome' AND pwd='6f8f57715090da2632453988d9a1501b';
e sarebbe, appunto, non vulnerabile.