SQL injection: cosa sono, come difendersi, consigli utili

Parliamo di SQL injection e di come difendere le applicazioni web.

il
Software architect e imprenditore digitale, Fondatore di IProgrammatori

Ricordo ancora quando nei primi anni 2000, ci fu l'exploit della produzione di siti web. Appassionati e aziende arricchivano il web di nuove realtà.
Ben presto agli operatori del settore fu noto come il consentire l'accesso a un sito web lo esponesse anche ai rischi di intrusione.
Una delle calamità maggiori che accomunava tantissimi siti web era l'attacco tramite SQL injection. La percentuale di siti web che prestava il fianco a questo tipo di attacco informatico era altissima.

La domanda a questo punto è: oggi cosa è cambiato? L'intrusione tramite SQL injection resta uno degli attacchi più comuni e col successo maggiore.

Cosa sono le SQL injection?

Per comprendere meglio cosa sono, è necessario comprendere l'architettura di un applicazione web.
Di base un'applicazione web è composta almeno da:

A - un'interfaccia utente (generalmente realizzata con un linguaggio di markup come HTML5, poi javascript e quanto serve).
B - un codice lato server che esegue delle operazioni, come l'elaborazione di un form di dati inviato dall'utente, l'autenticazione, ecc.
C - un database SQL che archivia dei dati.

Esistono architetture differenti: monolitiche, three-tier, Service-Oriented Architecture (SOA) e ultimamente a microservizi.

La cosa che accomuna tutti è che tramite l'interfaccia web (A) si leggono e scrivono dati nel database (c).

Facciamo un esempio? Quando ci sia autentica su un sito web, si forniscono le credenziali username e password che l'applicazione web deve confrontare "in un qualche modo" con i dati presenti nel database.

L'obiettivo di una SQL injection è far eseguire all'applicazione web delle query SQL arbitrarie sul database SQL (la vittima).
Le query possono essere distorsioni di quelle che dovrebbe eseguire l'applicazione (come modificare o invalidare la condizione WHERE) oppure ex nove.
Le query alterate possono essere sia di lettura che di scrittura (queste ultime, molto pericolose hanno lo scopo di alterare i dati e/o la struttura del database).

Da dove vengono eseguite le SQL injection?

Nulla di più ovvio: possono essere eseguite per mezzo di una richiesta alla pagina web che si aspetta dei parametri.

Esempio:

1) Tramite l'invio (POST) di un form di dati (pagina di login, iscrizione utente, ecc)
2) Passandole come parametro di GET alle pagine web del tipo "https://www.nomedelsitoweb.estensione/pagina.php?ID=*.
* qui viene passata l'iniezione di codice SQL arbitrario.

Esempio di SQL injection for dummies::

Mettiamo di avere:
1) una pagina di autenticazione che accetta fld_username e fld_password
2) lo strato applicativo che a basso livello esegue la query:

statement = "SELECT * FROM users WHERE username= '"+ fld_username + "' and password= '"+ fld_password + "'"

Mettiamo che:

L'attaccante invii come valore nei parametri di richiesta (fld_username e fld_password) il valore:

' OR '1' = '1

Cosa succede?

Ecco qui cosa verrà eseguito dal database:

statement = "SELECT * FROM users WHERE username= '' OR '1' = '1' and password= '' OR '1' = '1'"

OVVERO

<<estraimi tutto dalla tabella utenti DOVE username è uguale a '' oppure l'assioma '1' = '1' è vero (ed è ovvio che è vero) ... e fai lo stesso con la verifica della password>>

Che equivale a:

statement = "SELECT * FROM users"

E se l'attaccante passa come username "Admin" o "Administrator"? è facile che becchi l'account di amministrazione ed effettui il login al sistema come tale. Difatti sconsiglio sempre di usare account con tali nomi.

Quali sono gli errori palesi di progettazione che hanno permesso l'esecuzione della SQL injection?

1) Non è stato validato l'input (e ci si è fidati dell'utente)
2) Difatti non è stato eseguito l'eventuale replace (Escape) del carattere "apice" con un "doppio apice".

Volendo andare alla base: la query eseguita non è di tipo parametrico e quindi facilmente alterabile.
Ecco i classici caratteri pericolosi di cui eseguire l'escaping: \x00, \x1a, \n, \r, \, ', "

Come difendersi dalle SQL injection

L'injection SQL precedentemente mostrata è molto semplice, oggi ne esistono di veramente complesse e offuscate.
Inoltre hacker, lamer e compagnia utilizzano tools che collezionano gli url delle pagine web e le attaccano con migliaia di tentativi disparati.
Il concetto è: attacco più pagine web possibili con più tipologie di attacchi possibili per moltiplicare le possibilità di beccare pagine web vulnerabili ad attacchi specifici.

Esistono delle difese che vanno sempre implementate per opporre resistenza agli attacchi tramite sql injection, qui alcune utili:

1) Usare possibilmente solo query parametrizzate, stored procedure, librerie ORM (object-relational mapping) che generano statement SQL parametrizzati

2) Validare l'input: tipologia di dato, lunghezza, formato, contenuto
Se l'applicazione web si aspetta per un dato parametro un valore numerico e gli arriva una stringa di caratteri c'è qualcosa che non torna.
Se l'applicazione web si aspetta una email e il formato non è di una mail (vengono in aiuto le Regular Expression) c'è qualcosa di strano.

L'input deve essere sempre ripulito dai caratteri speciali (Escape) o keyphrase pericolose (quante probabilità ci sono che la stringa DROP TABLE sia un input ordinario?)

3) Fornire all'applicazione un account utente di database limitato per diminuirne le possibilità di manovra.
Sarebbe gravissimo che l'utenza consentisse di eseguire query del genere:

statement ="SELECT TABLE_NAME,COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS"

Di cosa si tratta? Si tratta di ottenere la lista di tutte le tabelle e colonne del database.

4) Non fornire informazioni utili agli attaccanti, ovvero, non visualizzare gli errori di dettaglio sulle pagine web ma reindirizzare l'utente a una pagina di cortesia generica.

5) In base all'architettura applicativa ragionare su come potrebbe essere utilizzata per un attacco.
Spunti utili possono arrivare dalla lettura degli argomenti trattati da OWASP (Open Web Application Security Project). Basta farsi un giro sul sito ufficiale.

6) Difendiamo l'applicazione web proteggendola dall'esterno (diamogli uno scudo)
Qualsiasi applicazione web deve essere aiutata a proteggersi e non bastano sempre e solo le competenze degli sviluppatori.

Una difesa importante è fornita dai WAF (Web Application Firewall). Si tratta di un sistema di difesa da posizionare davanti all'applicazione web.

Cosa sono i WAF? sono dei firewall che lavorano al livello 7 (applicativo) della pila ISO/OSI.
Fondamentalmente ispezionano il traffico HTTP in entrata (e volendo anche in risposta), assegnano un punteggio di pericolosità alla richiesta e, superato il livello di attenzione previsto, la bloccano.
Una richiesta bloccata non viene nemmeno eseguita dall'applicazione web (e si evita a monte che quest'ultima non sia in grado di gestirla).
Un WAF non si limita alla protezione da SQL injection ma include tante altre tipologie di attacco come cross-site scripting (XSS), path traversal, ecc.