• ModSenior

    [Guida] SQL Injection

    Cosa sono le SQL Injection
    SQL Injection è un termine con il quale si identifica una tecnica con il quale è possibile manomettere le query SQL in applicazioni nel quale non sono stati inseriti appositi controlli.
    Molto spesso negli script non viene considerata la sicurezza dell'applicazione, e questo può far si che un malitenzionato manometta il database o entri in possesso dei dati presenti nel database.

    Scopo della guida
    Lo scopo di questa guida è appunto quello di creare applicazioni sicure.
    Per fare ciò è necessario conoscere come si fà una SQL Inection, per sapere quali parti della applicazioni sono a rischio e provvedere a rendere questi attacchi impossibili.

    Configurazione di php - Magic_quotes
    Alcune volte potreste trovare differenza di configurazione di php, potrebbe esserci infatti la direttiva magic_quotes su ON, questa si occupa di fare un filtraggio di base a tutti gli input.
    Nella maggior parte dei casi questo filtraggio è molto utile e diminuisce moltissimo la possibilità di alterare le query, tuttavia presenta dei problemi nel caso in cui lavoriamo anche con i file.
    Passando tra un hosting e l'altro potrebbe comunque esserci differenza nell'impostazione di questa direttiva, per cui quello che era "sicuro" sull'hosting X potrebbe non esserlo più se passiamo all'hosting Y.
    Se fin ora molti programmatori si sono cullati su questa direttiva, da php 5.3 la direttiva è deprecata ed è stata rimossa con php 5.4, per cui d'ora in poi bisognerà fare molta attenzione alle SQL Injection. Nel caso in cui vogliamo settare la direttiva su OFF possiamo usare il seguente codice:

    [php]
    if(function_exists('set_magic_quotes_runtime'))
    {
    @set_magic_quotes_runtime(0);
    }
    [/php]

    Esempio 1 - Login

    Supponiamo di avere un form di login realizato cosi:
    index.html:
    [php]
    <form action="login.php" method="post">
    Username: <input type="text" name="user" />
    Password: <input type="password" name="pass" />
    <input type="submit" value="Login" />
    </form>
    [/php]

    login.php
    [php]
    $user = $_POST['user'];
    $pass = $_POST['pass'];
    $sql = mysql_query("SELECT * FROM utenti WHERE user = '$user' AND pass = '$pass'");
    if(mysql_num_rows($sql) > 0)
    {
    // Eseguo login
    }
    [/php]

    Vediamo come è possibile sfruttare una SQL Injection, inseriamo come user:

    TheDarkITA
    

    E come password:

    ' OR '1' = '1 
    

    Magicamente il nostro script ci farà passare come se esiste un utente con quel nick e con quella password.
    Se non ci credete, provate pure.

    Esempio 2 - Login più complessi
    Alcuni login controllano che venga restituito un solo record, questo non le rende immuni da SQL Injection.
    In questo esempio loggheremo con l'utente admin, e l'applicazione potrebbe darci privileggi maggiori.

    index.html:
    [php]
    <form action="login.php" method="post">
    Username: <input type="text" name="user" />
    Password: <input type="password" name="pass" />
    <input type="submit" value="Login" />
    </form>
    [/php]

    login.php
    [php]
    $user = $_POST['user'];
    $pass = $_POST['pass'];
    $sql = mysql_query("SELECT * FROM utenti WHERE user = '$user' AND pass = '$pass' LIMIT 1");
    if(mysql_num_rows($sql) == 1)
    {
    // Eseguo login
    }
    [/php]

    Vediamo come è possibile sfruttare una SQL Injection per autenticarci come admin, inseriamo come user:

    TheDarkITA
    

    E come password:

    ' OR user = 'admin
    

    Ed anche questa volta siamo entrati, come admin.

    Altre informazioni
    Effettuando una SQL Injection è possibile anche generare subquery, e manomettere query di update o delete, gli effetti potrebbero essere parecchio indesiderati anche in quei casi.
    In questi 2 esempi ci siamo limitati al caso del login, che è il semplice da capire, e permette a chi legge la guida di vedere quanti problemi possa provocare la mancanza di sicurezza per le applicazioni.
    In alcuni casi, con subquery, si potrebbe anche arrivare a recuperare l'intera lista di nomi utenti e password dell'applicazione. La cosa è più complicata ovviamente, e richiede delle query di partenza un pò particolari, che a me comunque è capitato di vedere utilizzate e quindi fate massima attenzione.

    Come ci si difende
    Bisogna effettuare il filtraggio dei dati di input sempre. Se ci aspettiamo ad esempio che un utente inserisca un dato numerico, controlliamo di aver ricevuto un numero e non una stringa di caratteri.
    Nei casi dei login, per difendersi bisognerebbe filtrare gli input cosi:
    [php]
    $user = mysql_real_escape_string($_POST['user']);
    $pass = mysql_real_escape_string($_POST['pass']);
    [/php]

    Difendersi è molto semplice, basta usare questa funzione infatti per le stringhe. Ma bisogna fare attenzione a non dimenticarlo mai, e pensare cosa può accadere se un utente manomette l'input inviando qualcosa che non ci aspettiamo normalmente di ricevere.