TL; DR
- L'applicazione accetta input, in questo caso 'Nancy', senza tentare di - disinfettare l'input, ad esempio sfuggendo a caratteri speciali
school => INSERT INTO student VALUES ( 'Nancy' ); INSERISCI 0 1
- L'inserimento di SQL si verifica quando viene manipolato l'input in un comando di database per - fare in modo che il server di database esegua arbitrariamente SQL
school => INSERT INTO student VALUES ( 'Robert' ); Studenti DROP TABLE ; - '); INSERISCI 0 1 TABELLA GOCCE
- I registri degli studenti ora sono andati - avrebbe potuto essere anche peggio!
scuola => SELEZIONA * DA studenti ;
ERRORE : relazione "studenti" fa non esiste
LINEA 1 : SELEZIONA * DA studenti ; ^
Questo elimina (elimina) la tabella degli studenti.
( Tutti gli esempi di codice in questa risposta sono stati eseguiti su un server di database PostgreSQL 9.1.2. )
Per chiarire cosa sta succedendo, proviamo con una semplice tabella contenente solo il campo del nome e aggiungiamo una singola riga:
school => CREATE TABLE studenti ( nome TEXT PRIMARY KEY );
AVVISO : CREATE TABLE / PRIMARY KEY sarà creare implicita indice "students_pkey" per tavolo "studenti" CREATE TABLE
scuola => INSERT INTO studenti VALORI ( 'John' ); INSERISCI 0 1
Supponiamo che l'applicazione utilizzi il seguente SQL per inserire i dati nella tabella:
INSERISCI AI VALORI degli studenti ( 'foobar' );
Sostituisci foobar
con il nome effettivo dello studente. Una normale operazione di inserimento sarebbe simile a questa:
- Input: Nancy
school => INSERT INTO student VALUES ( 'Nancy' ); INSERISCI 0
1
Quando eseguiamo una query sulla tabella, otteniamo questo:
scuola => SELEZIONA * DA studenti ;
nome
-------
John
Nancy
( 2 file )
Cosa succede quando inseriamo il nome di Little Bobby Tables nel tavolo?
- Input: Robert '); Studenti DROP TABLE; -
scuola => INSERIRE IN VALORI studenti ( 'Robert' ); Studenti DROP TABLE ; - '); INSERISCI 0 1 TABELLA GOCCE
L'iniezione SQL qui è il risultato del nome dello studente che termina la dichiarazione e include un separato DROP TABLE
comando ; i due trattini alla fine dell'input hanno lo scopo di commentare qualsiasi codice rimanente che altrimenti causerebbe un errore. L'ultima riga dell'output conferma che il server del database ha eliminato la tabella.
È importante notare che durante l' INSERT
operazione l'applicazione non controlla l'input di caratteri speciali e quindi consente l'inserimento di input arbitrari nel comando SQL. Ciò significa che un utente malintenzionato può inserire, in un campo normalmente destinato all'input dell'utente, simboli speciali come virgolette insieme a codice SQL arbitrario per causare l'esecuzione da parte del sistema di database, quindi iniezione SQL .
Il risultato?
scuola => SELEZIONA * DA studenti ;
ERRORE : relazione "studenti" fa non esiste
LINEA 1 : SELEZIONA * DA studenti ; ^
SQL injection è l'equivalente del database di una vulnerabilità di esecuzione di codice arbitrario remoto in un sistema operativo o in un'applicazione. Il potenziale impatto di un attacco con iniezione SQL riuscito non può essere sottovalutato: a seconda del sistema di database e della configurazione dell'applicazione, può essere utilizzato da un utente malintenzionato per causare la perdita di dati (come in questo caso), ottenere l'accesso non autorizzato ai dati o persino eseguire codice arbitrario sul computer host stesso.
Come notato dal fumetto XKCD, un modo per proteggersi dagli attacchi di iniezione SQL è quello di disinfettare gli input del database, ad esempio sfuggendo a caratteri speciali, in modo che non possano modificare il comando SQL sottostante e quindi non possano causare l'esecuzione di codice SQL arbitrario. Se si utilizzano query con parametri, ad esempio utilizzandoSqlParameter
in ADO.NET, l'input verrà almeno sanificato automaticamente per evitare l'iniezione di SQL.
Tuttavia, la disinfezione degli input a livello di applicazione potrebbe non arrestare tecniche di iniezione SQL più avanzate. Ad esempio, ci sono modi per aggirare la mysql_real_escape_string
funzione PHP . Per una maggiore protezione, molti sistemi di database supportano istruzioni preparate . Se implementati correttamente nel back-end, le istruzioni preparate possono rendere impossibile l'iniezione SQL trattando gli input di dati come semanticamente separati dal resto del comando.