sql injection
Manuel Ricci

SQL Injection: cos’è, come si fa e come ci si difende

Come funziona un attacco di SQL Injection e quali possono essere delle best practice da mettere in atto per prevenirli? Scopriamolo con questo articolo.

Indice

Questo articolo è stato pubblicato su LinkedIn il 15 settembre 2021

Oggi più che mai il dato è un componente essenziale dei sistemi d’informazione. I database sono delle raccolte di dati strutturati che aiutano le aziende a organizzare e gestire i dati dei propri clienti o qualunque sia l’uso per la quale il database è stato progettato.

Il principale linguaggio utilizzato per recuperare questi dati è SQL ed è l’acronimo di Structured Query Language. Permette, oltre al recupero, di performare diversi tipi di operazioni tra cui anche la manipolazione dei dati.

Nota bene: in questo articolo ci focalizzeremo maggiormente sul SQL Injection e quindi sui database relazionali, ma a fine articolo ho dedicato un breve paragrafo sulla medesima pratica, ma eseguita su database non relazionali (NoSQL).

Cos’è il SQL Injection?

Il SQL Injection appare nelle prime discussione pubbliche nel 1998 e in pratica si fa riferimento a quell’attacco che manipola le istruzioni SQL dinamiche, commentandone certi parti o concatenando condizioni che risulteranno sempre vere. Gli effetti di queste manipolazioni possono essere diversi, come ad esempio:

  • eliminazione dei dati
  • compromissione degli utenti
  • ottenimento dei dati di sistema
  • annullamento di transazioni

Questa tecnica sfrutta le vulnerabilità di sicurezza del codice applicativo che si interfaccia alla fonte dati SQL. Un esempio può essere un form di login, per la quale, se non vengono opportunamente filtrati i dati inseriti, potranno essere sfruttati per effettuare un attacco di SQL Injection.

La OWASP Top 10 inserisce l’injection (SQL e NoSQL) tra i principali attacchi informatici ai danni di aziende.

In questo articolo voglio mostrare come funziona esattamente un attacco di SQL Injection e quali sono le best practice per proteggersi. In più, come già anticipato, apriremo una piccola parentesi sui database NoSQL, che non sono esenti da queste genere di attacchi.

Come funziona il SQL Injection?

I tipi di attacchi che possono essere performati dipendono dal database engine. In generale il SQL Injection prende di mira le istruzioni SQL dinamiche. Un’istruzione SQL dinamica è generata durante la fase di esecuzione del codice e usa come parametri i dati presi da un form o da una stringa URI.

Supponiamo di aver implementato un semplice form di login come quello che segue:

<form action='index.php' method="POST">
   <input type="email" name="email" required="required"/>
   <input type="password" name="password" required="required" />
   <input type="checkbox" name="remember_me" value="Ricordami"/>
   <input type="submit" value="Accedi"/>
</form>
  • Il form presenta un campo per l’inserimento di una mail e di una password i quali verranno inviati al file index.php
  • La sessione di accesso può essere memorizzata in un cookie. Lo abbiamo dedotto dalla casella di controllo Ricordami. 
  • Utilizza il metodo POST per inviare i dati. Ciò significa che i valori non vengono visualizzati nell’URL.

Supponiamo quindi che l’istruzione SQL eseguita nel backend per il controllo dell’utente si la seguente:

SELECT * FROM users WHERE email = $_POST['email'] AND password = md5($_POST['password']);
  • L’istruzione usa i valori dell’array $_POST[] direttamente, senza una precedente attività di sanificazione.
  • La password è cifrata con un algoritmo MD5.

Con SQL Fiddle possiamo inscenare un attacco di SQL Injection.

Preparazione dello scenario

In SQL Fiddle inserire nel pannello di sinistra questo codice:

CREATE TABLE `users` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `email` VARCHAR(45) NULL,
  `password` VARCHAR(45) NULL,
  PRIMARY KEY (`id`));
  
  
INSERT INTO users (email,password) VALUES ('m@m.com',md5('abc'));

Cliccare sul pulsante Build Schema

Scrivere la seguente query nel pannello di destra:

SELECT * FROM users

Cliccare il pulsante Run SQL e dovrebbe restituire qualcosa di simile a questo:

Peformare l’attacco

Continuando le nostre supposizioni, l’utente inserisce come email admin@admin.sys e password 1234. Prelevando i valori direttamente dall’array $_POST[] senza previa sanificazione la query che verrà eseguita sarà la seguente:

SELECT * FROM users WHERE email = 'admin@admin.sys' AND password = md5('1234');

Questa istruzione può essere sfruttata commentando la parte della password e concatenando una condizione sempre vera.

Il nostro utente, ormai attaccante, inserisce come email xxx@xxx.xxx’ OR 1 = 1 LIMIT 1 — ‘ ] e come password xxx.

L’istruzione SQL dinamica stavolta sarà la seguente:

SELECT * FROM users WHERE email = 'xxx@xxx.xxx' OR 1 = 1 LIMIT 1 -- ' ] AND password = md5('xxx');
  • xxx@xxx.xxx termina con una virgoletta che chiude la stringa
  • OR 1 = 1 LIMIT 1 è una condizione che risulterà sempre vera e restituirà un solo record.
  • — ‘ AND … è un commento SQL che elimina la parte relativa alla password.

Grazie all’evidenziatore di sintassi di SQL Fiddle sarà possibile vedere la parte commentata.

Se la query dovesse essere eseguita (basta cliccare sul pulsante Run SQL), ci verrà restituito un risultato.

Fosse stato un sito reale, come direbbero gli hacker anni 80, siamo dentro!

No alt text provided for this image

Come prevenire gli attacchi di SQL Injection

Dal SQL Injection non ci si difende, ma si previene con tutta una serie di policy atte a mitigare questo genere d’attacco. In particolar modo è consigliato:

  • Non fidarsi mai dell’input dell’utente: deve essere sempre sanitificato prima di essere usato in una istruzione SQL dinamica.
  • Stored procedures: la quale incapsula le istruzioni SQL trattando tutti gli input come parametri.
  • Prepared statement: a differenza delle interrogazioni classiche, le dichiarazioni preparate non contengono i singoli vari, ma vengono sostituiti in un secondo momento con i valori reali presenti a sistema.
  • Espressioni regolari: perfette per individuare pattern noti, come quelli visti durante la procedura d’attacco.
  • Fornire i giusti privilegi agli utenti: dare solo i privilegi necessari è sicuramente un’ottima cosa per evitare che vengano performate istruzioni al di sopra delle capacità di uno specifico ruolo utente.
  • Messaggi di errore: Non mostrare mai l’errore SQL nell’interfaccia utente, potrebbero essere esposte più informazioni di quello che si pensa.

NoSQL Injection

Come anticipato ad inizio articolo, vorrei aprire una piccola parentesi anche sui database NoSQL.

Per i meno esperti in lettura un brevissimo ripasso. I database NoSQL sono quelli che non usano SQL per le query e a differenza dei database relazionali non richiedono la predefinizione di schemi. In NoSQL i dati possono essere aggiunti senza una chiara definizione dello schema. Proprio grazie a questa flessibilità, a differenza dei database relazionali, NoSQL può scalare facilmente orizzontalmente.

Se non usa SQL, come può essere soggetto a SQL Injection? I database NoSQL come MongoDB usano comunque le query per interrogare il database basandosi sull’input dell’utente. Ricordi la prima policy di prevenzione? Non fidarsi mai dell’input dell’utente.

La differenza principale tra SQL e NoSQL injection è la grammatica e la sintassi della query. 

L’injection SQL difficilmente funzionerà anche per l’injection NoSQL. I database NoSQL non hanno un linguaggio standardizzato. Tuttavia, la sintassi dei loro linguaggi è molto simile (dato che sono progettati per fare la stessa cosa).

Il NoSQL injection consiste nell’attaccare applicazioni costruite su stack MEAN o MERN. Quando passano i dati, le applicazioni MEAN e MERN utilizzano JSON, che è la stessa cosa utilizzata da MongoDB. L’iniezione di codice JSON in un’applicazione MEAN può consentire attacchi di iniezione contro un database MongoDB.

Per quanto SQL e NoSQL differiscono, le policy da adottare sono praticamente le stesse viste in precedenza con alcune differenze dettate semplicemente dalla natura delle due tecnologie.

Conclusioni

Con questa prima introduzione al SQL Injection sarà sicuramente più chiara la dinamica di un attacco e come prevenire spiacevoli sorprese. Per ulteriori informazioni sugli strumenti di prevenzione a disposizione si possono consultare le documentazioni dei linguaggi e delle tecnologie impiegate. L’evergreen rimane sempre e comunque sanificare!

Vuoi altri contenuti così, ma nella tua inbox?