sicurezza Intermediate 5 min

A05:2025 Injection: quando i dati diventano comandi

SQL injection, ORM, XSS e OS command injection: un solo principio, quattro bersagli

· 984 parole

Un'unica idea sta dietro nomi diversi: SQL injection, XSS, OS command injection, LDAP injection. In ogni caso, un interprete (un database, un browser, la riga di comando, una directory LDAP) riceve dati inseriti da chi naviga e li tratta come istruzioni invece che come semplice testo. OWASP conferma che XSS e SQL injection rientrano entrambe in questa unica categoria: XSS con frequenza altissima (oltre 30.000 CVE) e impatto singolo più contenuto, SQL injection più rara ma con impatto molto più devastante (oltre 14.000 CVE).

Nella vita reale: è come consegnare un modulo a un impiegato che esegue alla lettera qualunque cosa ci scrivi sopra, anche se nel campo «nome» scrivi «cancella tutti gli archivi». Se l'impiegato non distingue mai tra dato da registrare e ordine da eseguire, qualunque cosa scrivi diventa un comando.

1. SQL injection: il bypass classico

Lo scenario più comune è una query costruita incollando direttamente l'input di chi naviga dentro il testo SQL:

$query = "SELECT * FROM utenti WHERE id = '" . $_GET['id'] . "'"; 
$risultato = $pdo->query($query);

Inserendo come id il valore ' OR '1'='1' -- , la query diventa una condizione sempre vera seguita da un commento SQL che cancella qualunque controllo scritto dopo: il risultato non è più il record richiesto, ma l'intera tabella, o peggio, un dato che permette di autenticarsi senza conoscere nessuna password.

Una query con l'input incollato dentro è come una frase con uno spazio vuoto da riempire: «Cerca l'utente con id = ___». Se lasci che chi scrive possa inserire anche la punteggiatura, non riempie solo lo spazio: può chiudere la frase in anticipo e aggiungerne una nuova tutta sua, con un significato completamente diverso.

Fonte: la OWASP Top 10:2025, categoria A05, descrive questo come lo scenario di iniezione SQL più comune tramite concatenazione diretta dell'input. 

2. Prepared statement: separare i dati dai comandi

La difesa raccomandata da OWASP è netta: tenere sempre i dati separati dal testo della query, usando un'interfaccia parametrizzata. In PHP, questo significa PDO con un prepared statement: il segnaposto ? (o un parametro nominato) non fa mai parte del testo SQL, viene sempre trattato come valore.

$stmt = $pdo->prepare('SELECT * FROM utenti WHERE id = ?'); 
$stmt->execute([$_GET['id']]); 
$risultato = $stmt->fetch();

Con un prepared statement, il valore di id, anche se fosse esattamente ' OR '1'='1' -- , viene trattato sempre e solo come una stringa da cercare, mai come parte della struttura della query: la ricerca semplicemente non trova nessun utente con quell'id strano, e si ferma lì.

Fonte ufficiale: la OWASP Top 10:2025, sezione «How to prevent» di A05, indica come opzione preferita una safe API che eviti del tutto l'interprete o fornisca un'interfaccia parametrizzata. https://owasp.org/Top10/2025/

3. ORM: aiuta, ma non è immune per definizione

Un query builder o un ORM riducono il rischio, ma non lo eliminano da soli: restano vulnerabili se, al loro interno, si passa comunque una stringa SQL costruita per concatenazione invece di usare i loro metodi parametrizzati.

// vulnerabile: SQL grezzo concatenato, anche se passato attraverso l'ORM $utenti = DB::select("SELECT * FROM utenti WHERE nome = '" . $richiesta->nome . "'"); // sicuro: il query builder gestisce da solo il parametro $utenti = DB::table('utenti')->where('nome', $richiesta->nome)->get();

Lo stesso vale, avverte OWASP, per le stored procedure: restano vulnerabili se al loro interno concatenano query e dati con istruzioni dinamiche invece di usare parametri propri.

4. XSS: quando il bersaglio è il browser, non il database

Per l'XSS l'interprete bersaglio non è un database, ma il browser: se l'input di chi naviga finisce nell'HTML della pagina senza essere codificato, il browser lo interpreta come markup o script invece che come semplice testo da mostrare.

// vulnerabile: il nome finisce diretto nell'HTML 
echo '<p>Ciao, ' . $_GET['nome'] . '</p>'; 

// sicuro: htmlspecialchars neutralizza i caratteri speciali dell'HTML 
echo '<p>Ciao, ' . htmlspecialchars($_GET['nome']) . '</p>';

Immagina di passare un bigliettino in classe che, invece di contenere solo un messaggio da leggere, include un'istruzione nascosta: «appena leggi questa riga, alzati e urla». Chi legge alla lettera, senza distinguere tra testo e istruzione, esegue quello che c'è scritto invece di limitarsi a leggerlo.

5. OS command injection: quando il bersaglio è il sistema operativo

Un terzo bersaglio comune è la riga di comando del sistema operativo stesso: se l'input di chi naviga finisce dentro un comando eseguito dal server, un carattere speciale della shell (come il punto e virgola) può aggiungere un secondo comando del tutto estraneo a quello previsto.

// vulnerabile: l'input finisce diretto nel comando di sistema 
exec('ping -c 4 ' . $_GET['host']);

Inserendo come host il valore example.com; cat /etc/passwd, il punto e virgola chiude il comando ping e ne fa partire un secondo, completamente diverso, con lo stesso livello di privilegi del processo PHP.

// piu' sicuro: escapeshellarg neutralizza i caratteri speciali della shell 
exec('ping -c 4 ' . escapeshellarg($_GET['host']));

Fonte: il manuale ufficiale PHP per escapeshellarg() ne descrive il funzionamento per neutralizzare gli argomenti passati a comandi di shell. 

Lo stesso principio, con lo stesso tipo di difesa (separare sempre dato e comando, mai concatenarli), vale anche per interpreti meno comuni ma comunque coperti dalla stessa categoria OWASP, come LDAP o i database a documenti: cambia l'interprete bersaglio, non il principio.

In sintesi

Il principio che unifica tutta la categoria è uno solo: non fidarti mai di ciò che arriva da chi naviga abbastanza da lasciarlo mescolare con i tuoi comandi, qualunque sia l'interprete che lo riceve. Un prepared statement per SQL, un query builder usato correttamente per l'ORM, htmlspecialchars() per l'HTML, escapeshellarg() per la shell: strumenti diversi per lo stesso identico principio, separare sempre il dato dal comando.

Per vedere questi due attacchi (SQL injection classica e UNION injection) funzionare davvero, stò preparando il primo Laboratorio pratico di PillsWeb, che sarà dedicato esattamente a questa pillola: una piccola applicazione volutamente vulnerabile da scaricare e sfruttare passo passo, nella sezione Laboratori del sito.

Accedi o registrati per votare, salvare o commentare la pillola

Commenti (0)

Registrati per commentare, fare domande e proporre l'argomento della prossima pillola (oppure accedi se hai già un account).

Nessun commento. Sii il primo a scrivere qualcosa.

Pillole correlate