Nei due articoli relativi a Inviare i dati di un form per mail tramite PHP, è emersa la mancanza di protezioni dalle query injection.
In questi articoli, allora, voglio parlarvi di queste query che possono essere pericolose per i siti e voglio mostrarvi come poterle evitare e quindi come proteggere, per esempio, un sistema di login da codici malevoli.
La SQL injection è una tecnica di hacking mirata a colpire le applicazioni web che si appoggiano su un database di tipo SQL. Questa tecnica sfrutta l’inefficienza dei controlli sui dati ricevuti in input ed inserisce codice maligno all’interno di una query SQL.

Le conseguenze prodotte sono imprevedibili per il programmatore: l’SQL Injection permette al malintenzionato di autenticarsi con ampi privilegi in aree protette del sito (ovviamente, anche senza essere in possesso delle credenziali d’accesso) e di visualizzare e/o alterare dati sensibili.
Un caso pratico a cui poter pensare è un campo di autenticazione molto comune, come il login alla propria webmail. Normalmente inseriamo username e password per poter leggere la posta elettronica, lo script si collega al database, verifica le nostre autorizzazioni e ci consente l’accesso, tutto questo si realizza tramite interrogazioni SQL.
Ma cosa succede se un utente malizioso inserisce caratteri propri del linguaggio T-SQL? come ad esempio l’apostrofo ‘, il doppio trattino –, il punto e virgola ; il punto interrogativo ? o se la pagina con i campi di login non è sufficientemente protetta e controllata, se in essa non viene prevista la validazione dell’input? quindi l’aggressore può modificare la query a suo piacimento.
Naturalmente non basta una virgola per far cadere il sistema nelle mani dell’aggressore, ma è un buon punto di partenza. Modificando le query, come vedremo più avanti, è possibile avere accesso ad alcuni dati senza autorizzazione, eludere i sistemi di autenticazione e addirittura far eseguire veri e propri comandi al server web (ad esempio un listato delle directory, o una lettura del registro di Windows).
Ma vediamo in maniera più dettagliata questo esempio pratico. Supponiamo di avere una pagina con un form che permette di immettere lo username e la password per accedere a una qualsiasi zona riservata di un sito:
<form action='login.php' method='post'> Username: <input type='text' name='user' /> Password: <input type='password' name='pwd' /> <input type='submit' value='Login' /> </form>
Questa potrebbe essere la pagina index.php per effettuare il login al sito o al servizio a cui si vuole accedere. Si tratta di una pagina molto semplice con due campi di tipo input e il pulsante di invio dei dati. Dopo che l’utente ha inserito i dati nel form premendo il pulsante di invio viene caricata la pagina login.php il cui contenuto può essere il seguente:
{ < ?php //Prepara la query, in una variabile $query = "SELECT * FROM users WHERE user='".$_POST['user']."' AND pwd='".$_POST['pwd']."'"; //Esegue la query (supponiamo che sia già aperta una connessione valida al database e $db è lo stato) $sql = mysql_query($query, $db); //Conta il numero di righe trovate (se questo numero è maggiore di 0 i dati immessi sono corretti) if(mysql_affected_rows($sql)>0) { //Esegue la convalida dell'autenticazione e permette l'accesso a pagine protette } ?>
L’attacco di SQL-injection consiste nell’immettere nello script PHP dati arbitrari facendo uso delle caselle di testo del form. Se lo script non compie i dovuti controlli, ipotizzando, per esempio, l’esistenza dell’utente di nome pippo e, quindi, con user pippo e come password ‘ OR user=’pippo per accedere con le credenziali dell’utente pippo. In tal caso, infatti, la query per il database diventerà:
SELECT * FROM users WHERE user='pippo' AND pwd='' OR user='pippo'
La disgiunzione inclusiva OR restituisce il valore logico true se una delle due condizioni è vera. La condizione per l’utente pippo è verificata e quindi il login viene effettuato con i conseguenti danni che potrebbero derivare da una intrusione indesiderata.
Ancora nessuna risposta per SQL injection, cos’è e come prevenire, Parte I