Cos'è un attacco SQL Injection

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:


Nome Utente:
Password:

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".



Nome Utente:
Password:

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:



Nome Utente:
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:

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:



Nome Utente:
Password:

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.


query multiple

Si forzi un errore nella query di interrogazione del database, inserendo (con union) nel campo username una seconda query:



Nome Utente:
Password:

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:



Nome Utente:
Password:

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:



Nome Utente:
Password:

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