L’SQL injection è una tecnica di hacking che, sfruttando alcuni errori nella programmazione di pagine web, permette di aggredire, partendo dal frontend, un database relazionale interrogabile via SQL.

Per consentire questa aggressione è necessario sia presente un input dell’utente (dal frontend al database) e che l’input dell’utente non sia sanificato (lato backend). L’aggressore approfitterà di queste due presenze per iniettare codice SQL e aggredire il database.

L’SQL injection è particolarmente pericoloso poiché non richiede l’uso di strumenti particolari ma solo di un PC e di un browser per la navigazione sul web e non è legato all’utilizzo di un particolare linguaggio di programmazione web based (PHP, Java ecc.) né tantomeno a quello di un particolare server DB (Oracle, Mysql, Microsoft SQL Server, etc.).

Una programmazione poca attenta alla sicurezza può accrescere in modo significativo le vulnerabilità mettendo in serio pericolo le logiche di elaborazione che costituiscono le transazioni SQL.

SQL INJECTION

SQL injection: come funziona

Iniziamo col premettere che, per comprendere la tecnica di questo attacco, è necessario capire come funziona la comunicazione tra un server erogatore di servizi (in cui risiede il DB) ed un client che usufruisce di tali servizi.

Sebbene esistano diversi tipi di sistemi per la gestione di database relazionali, tutti sono potenzialmente vulnerabili a questa infezione. Gli esempi riportati in questo articolo si riferiscono al software di gestione database MySQL ed al linguaggio di programmazione PHP per lo sviluppo delle applicazioni lato server.

Ipotizziamo l’accesso di un utente al suo profilo personale per l’erogazione di un servizio: il visitatore digita l’indirizzo della pagina di login che risiede su di un server (sito web). Il server web elabora la pagina in locale e produce, come risultato, una pagina in HTML inviandola al browser del client che si occuperà di visualizzarla sullo schermo del visitatore.

Per l’erogazione del servizio, il visitatore inserirà le proprie credenziali sul form di login e quest’ultimo invierà i dati al server web che tramite l’esecuzione di uno script PHP, interrogherà il proprio DB (MySQL).

Il DB solo in caso di corrispondenza delle credenziali risponderà al server con i dati richiesti. Il server web provvederà ad inviare i dati al browser del client ed il visitatore, come risultato di questo processo, visualizzerà le informazioni relative al servizio richiesto.

SQL injection: obiettivi d’attacco

Al fine di scongiurare lo sfruttamento di eventuali vulnerabilità, a livello di programmazione, è necessario adottare ottime misure di protezione. Particolare attenzione deve essere posta alla messa in sicurezza del codice deputato alla gestione di moduli di autenticazione e pagine di ricerca che rappresentano le potenziali porte di accesso.

Un hacker esperto di sintassi SQL, infatti, può inviare particolari istruzioni attraverso le pagine del sito che prevedano un dialogo con il DB, con l’obiettivo di ottenere un accesso non autorizzato all’applicazione stessa, per recuperare informazioni, dati sensibili e modificarli o eliminarli.

SQL injection: preliminari ed anatomia di un attacco

Le osservazioni preliminari di un attaccante riguardano il modo in cui l’applicazione interagisce con un server DB e sono fondamentali per la ricerca di informazioni necessarie a risalire alla struttura dell’applicazione.

Il passo successivo è quello di interpretare i messaggi di errore che un applicativo restituisce in caso di inserimenti anomali. Qualora ogni tipo di messaggio di feedback sia stato disabilitato, è possibile utilizzare tecniche di sniffing per l’intercettazione del traffico di rete.

Un attacco SQL injection prevede, ad esempio, l’inserimento di termini specializzati nei campi di un modulo web in modo da inviare al database comandi inconsueti e imprevisti sfruttando l’applicazione stessa.

Come esempio, mostrato ad uso esclusivamente didattico, consideriamo il seguente caso di cui si è preso spunto dalla pagina OWASP dedicata al testing SQL injection.

La query MySQL è la seguente:

SELECT * FROM utenti WHERE username = ‘$_POST[“nominativo”]’ AND password= ‘$_POST[“password”]’

Lo scopo di questo comando, inviato tramite un form web, ad esempio, è quello di recuperare delle informazioni dalla relativa tabella utenti qualora le credenziali risultino nella tabella stessa.

Se, come visto, non c’è alcuna forma di validazione dell’input, un potenziale attaccante potrebbe provare ad inserire le seguenti username e password:

$_POST[“nominativo”]= 1 ‘OR’ 1 ‘=’ 1

$_POST[“password”]= 1 ‘OR’ 1 ‘=’ 1

La combinazione d’uso delle virgolette con l’operatore logico “OR” genera il seguente comando SQL modificato ed inviato al DB:

SELECT * FROM utenti WHERE nome = ‘1’ OR ‘1’ = ‘1’ AND password=’1’  OR ‘1’ = ‘1’

La clausola WHERE viene ora soddisfatta da ogni voce della tabella utenti in quanto la parte introdotta dall’istruzione logica OR è sempre verificata quindi tale Query può causare la restituzione del primo o di più valori della tabella utenti.

È possibile, inoltre, includendo dei delimitatori di commenti (/*…*/), provare a far ignorare addirittura alcune parti delle Query, come ad esempio quella relativa al campo password.

SELECT * FROM utenti WHERE ((nome = ‘1’ OR ‘1’ = ‘1’)) /*’) AND (password=hash(‘sha256’, $_POST[“password” ]))))

Gli esempi soprariportati ci fanno capire che è possibile carpire le credenziali amministrative di un DB poiché solitamente il primo utente della lista è proprio l’account admin.

L’hashing delle password è sempre utile per garantire la riservatezza delle stesse, ma non sempre è sufficiente a garantirne l’autenticazione, in quanto come visto l’accesso tramite parola chiave può essere bypassato.

SQL injection: hacking alle applicazioni Web

SQL injection: l’estensione di MySQL

Per prevenire l’iniezione di Query è importante, in fase implementativa, una programmazione che preveda un controllo di tutte le potenziali porte di accesso all’archivio di gestione dei dati (quali form, pagine di ricerca ed eventuali altri moduli che implicano un’interrogazione SQL), la validazione degli input, le Query parametrizzate tramite template e un’adeguata gestione del reporting degli errori.

Ecco alcuni accorgimenti da adottare:

  • prestare attenzione all’utilizzo degli elementi di codice SQL potenzialmente a rischio (virgolette singole e parentesi) che potrebbero essere integrati con opportuni caratteri di controllo e sfruttati per usi non autorizzati;
  • usare l’estensione MySQLi;
  • disattivare sui siti la visibilità delle pagine degli errori. Spesso tali informazioni si rivelano preziose per risalire all’identità e alla struttura dei server DB.

Una codifica accurata può ridurre la vulnerabilità di un’applicazione web. Una buona soluzione risulta quella di utilizzare tra le librerie messe a disposizione da PHP, l’estensione MySQLi (MySQL improveded) che apporta delle migliorie al MySQL in particolare mettendo a disposizione due approcci di programmazione:

  • procedurale (uso di tradizionali funzioni);
  • orientato agli oggetti (uso di classi e metodi).

SQL injection: validazione dell’input

Applicando il metodo mysqli::real_escape_string è possibile sanificare caratteri speciali e di controllo potenzialmente pericolosi. Qualora si abbia, invece, necessità di igienizzare particolari caratteri non gestiti dal metodo si può intervenire tramite operazioni di replace manuale.

Un’altra soluzione per la validazione degli input è rappresentata dalla conversione in esadecimale dei caratteri costituenti un’istruzione SQL.

In PHP si utilizza la funzione bin2hex(). Secondo questa prassi l’istruzione in esadecimale, prima di essere eseguita, viene riconvertita in una stringa tramite la funzione unhex() di MySQL. Così facendo la sequenza di caratteri riconvertita, non essendo intrepretata come comando, non rappresenta più un potenziale pericolo.

SQL injection: Query parametrizzate

Un’altra tecnica di difesa da usare per attenuare le conseguenze di un SQL injection sono le Query parametrizzate che consentono di definire la sintassi delle istruzioni, distinguendo il codice dai dati indipendentemente dall’input ricevuto, prima di passare i parametri alla Query. In questo modo non è possibile alterare la finalità di una Query attraverso interventi malevoli esterni.

Riprendendo il precedente esempio, se l’attaccante inserisse come username la stringa “‘1’ OR ‘1’ = ‘1’”, la Query adeguatamente parametrizzata risulterebbe immune perché cercherebbe un nome utente corrispondente lettera per lettera alla stessa stringa.

Questo format prevede tre passaggi principali:

  • la preparazione: viene creato un template di istruzione SQL dove si utilizzano dei parametri segnaposto ? “ placeholder” per indicare i valori dei dati da specificare che verrà inviato al database tramite il metodo prepare().

$mysqli->prepare(“SELECT * FROM login WHERE username = ? AND password = ?”);

  • l’analisi: il template viene analizzato, compilato e memorizzato senza eseguirlo tramite il metodo bind(). Vengono associati le variabili con i segnaposti ed il tipo di dato atteso, rispettando l’ordine di posizione.

    $mysqli->bind_param(‘ss’,$username,$password);

    Le variabili $username e $password attesi devono essere delle stringhe ‘ss’. Altri tipi previsti sono:

      1. i: tipo dato numero intero;
      2. d: tipo dato numeri double;
      3. b: tipo di dato binario;
    • l’esecuzione: l’applicazione, una volta associati i valori ai parametri, esegue l’istruzione tramite il metodo execute().

    $result = $mysqli->execute();

    Dopo aver valutato l’esito della variabile $result è possibile proseguire con il resto del codice per eventuali operazioni di inserimento, modifica o cancellazione dei record interessati.

    SQL injection: hacking alle applicazioni Web

    Esempio di SQL Injection

    Ipotizziamo di avere una pagina Web che estrae il contenuto di un articolo da un database. Immaginiamoci un URL di questo tipo:

    www.sitovulnerabile.it/articoli/leggi-articolo.php?id=4

    Il codice della pagina, semplificato all’osso fino a mostrare solo la stringa per la Query, potrebbe essere:

    $query=”SELECT articolo FROM articoli WHERE id='”.$_GET[“id”].”‘”;

    Per capire se la pagina è vulnerabile ad una SQL Injection, un malintenzionato potrebbe modificare l’URL della pagina e provare ad effettuare una SQL Injection. Per esempio, se scrivesse qualcosa tipo (in grassetto la SQL Injection):

    www.sitovulnerabile.it/articoli/leggi-articolo.php?id=4′ OR id=1 ORDER BY id

    Questo trasmetterebbe una Query così strutturata (in grassetto la SQL Injection):

    SELECT articolo FROM articoli WHERE id=’4′ OR id=1 ORDER BY id;

    L’obiettivo è caricare l’articolo con id=1 e non con id=4. Per farlo è sufficiente essere certi che l’articolo con id=1 esista, ed è facile da scoprire, è sufficiente caricare l’URL corretto www.sitovulnerabile.it/articoli/leggi-articolo.php?id=1.

    Se la pagina mostrata con l’URL: www.sitovulnerabile.it/articoli/leggi-articolo.php?id=1

    È uguale alla pagina mostrata con URL: www.sitovulnerabile.it/articoli/leggi-articolo.php?id=4′ OR id=1 ORDER BY id allora la pagina Web è esposta ad una vulnerabilità SQL Injection.

    Conclusioni

    L’applicazione di adeguati accorgimenti nello sviluppo del software contro l’SQL injection non può garantire l’assoluta inviolabilità di un’applicazione dinamica web/db based, ma può ridurre la probabilità di successo dei tentativi di attacco.

    Restano sempre valide alcune regole di prevenzione:

    • aggiornare i tools in uso per la produzione e la gestione, con le ultime release e patch che i fornitori legittimi mettono periodicamente a disposizione;
    • adottare una corretta politica per la gestione dei privilegi SQL per le utenze, prestando particolare attenzione alla custodia e robustezza delle password e disattivando gli account amministrativi convenzionali utilizzandone altri opportunamente creati al bisogno.

    La sicurezza delle Web Application è una tematica in cui noi di Nexsys teniamo molto. Nel nostro corso CyberSecurity ETHICAL HACKER v11 tale argomento merita una sezione dedicata che vi permetterà, al termine del corso, di conoscere come agiscono i nostri nemici aumentando la possibilità di difendersi e di reagire ad attacchi ed incidenti.