SQL injection: non incollare mai il testo dell'utente in una query

Le query di questo sito le digiti tu di proposito. In un'applicazione parte del testo di una query arriva da un modulo, un URL o un'API. Se quel testo viene incollato nel SQL, un visitatore può cambiare cosa fa l'istruzione. Questa pagina mostra l'errore sul database del forno, poi la correzione. Non è una guida per attaccare altri sistemi.

La query che intendevi

Supponi che un'app cerchi un cliente per cognome. Il SQL previsto è un filtro solo su quel nome.

SELECT first_name, last_name
FROM customers
WHERE last_name = 'Lopez'
ORDER BY customer_id;

Risultato: Ana Lopez, una riga.

Cosa può fare il testo incollato

Se l'app costruisce l'istruzione come `WHERE last_name = '` più quello che ha digitato il visitatore più `'`, allora inserire altro SQL in quella stringa cambia il filtro.

La query sotto è la stessa istruzione dopo che qualcuno digita un cognome che non chiude le virgolette e aggiunge `OR 1 = 1`. `1 = 1` è sempre vero, quindi il WHERE non restringe più le righe. Lo stesso tipo di bug su UPDATE o DELETE senza un WHERE stretto può cambiare o rimuovere ogni riga.

SELECT first_name, last_name
FROM customers
WHERE last_name = 'Lopez' OR 1 = 1
ORDER BY customer_id;

Risultato: Tutti e otto i clienti. Il filtro sul nome non limita più il risultato.

La correzione: parametri associati

Non unire il testo dell'utente al SQL. Invia l'istruzione con un segnaposto e passa il valore a parte. PostgreSQL usa `$1`, `$2` e così via. Il database tratta il valore come dati, mai come sintassi, così un cognome che sembra SQL resta un cognome.

La query che scrivi è allora sempre `WHERE last_name = $1`. Librerie e ORM la chiamano query parametrizzata o prepared statement. Devi comunque usarla: un ORM che concatena stringhe ha lo stesso bug.

SELECT first_name, last_name
FROM customers
WHERE last_name = 'Lopez'
ORDER BY customer_id;

Risultato: Di nuovo Ana Lopez: la ricerca con un valore associato, mostrata qui con un letterale perché questo editor non ha uno strato applicativo.

Domande comuni

Basta racchiudere il valore tra apostrofi extra?
No. Si dimentica un escape, le codifiche differiscono e i numeri non sono tra virgolette. I parametri associati evitano tutta questa classe di errori.
Un ORM significa che posso ignorarlo?
Solo se ogni query passa dalla sua API dei parametri. Le stringhe SQL grezze in un ORM sono ancora SQL concatenato. Preferisci il query builder o `execute(sql, [value])`.
E UPDATE e DELETE?
La stessa regola: il WHERE deve usare parametri, mai testo incollato. Un WHERE mancante o rotto su quelle istruzioni cambia un'intera tabella in un colpo.

Esercitati