Qual è il significato dell'iniezione SQL? Non sono in grado di capire il termine. E quali problemi potrebbero essere causati dall'iniezione SQL?
Qual è il significato dell'iniezione SQL? Non sono in grado di capire il termine. E quali problemi potrebbero essere causati dall'iniezione SQL?
L'iniezione SQL si verifica più comunemente quando un programmatore crea un comando SQL aggiungendo insieme (o interpolando) le stringhe, usando l'input fornito dall'utente.
es. Immagina questo estratto da un pezzo vulnerabile di pseudocodice di autenticazione utente (login) da un'applicazione web fittizia.
username = getPostData( "username" );
password = getPostData( "password" );
sql = "select id, username from users'
+ ' where username='" + username + "' and password='" + password +"'";
result = executeQuery( sql );
if (result[ 0 ]) {
loginUser( result[ 0 ][ 'id' ] );
print "You are logged in as " + encodeAsHtml( result[ 0 ][ 'username' ] );
}
A prima vista si potrebbe pensare che questo sia ragionevole, ma il problema è che non fa distinzione tra i dati forniti dall'utente e il codice SQL; i dati possono essere trattati come codice . Ciò significa che un utente malintenzionato può modificare la logica dell'istruzione SQL.
Un utente malintenzionato potrebbe ignorare completamente la protezione dell'account di accesso se potrebbe modificare la logica del comando SQL per produrre una risposta che garantisce che almeno una riga venga sempre restituita.
Ad esempio, se ha inserito un nome utente reale bob
, ma inserisce la password come:
' or 1=1 --
Quindi questo gli concederebbe l'accesso all'account di qualcun altro. Questo perché SQL risultante sarebbe simile a questo:
select id, username
from users
where username='bob' and password='' or 1=1 --'
Si noti che l'espressione logica 1=1
valuta sempre true. Si noti inoltre che il vettore di iniezione termina con due trattini, che contrassegna il resto della riga come un commento. Quindi l'SQL è logicamente lo stesso di
select id, username
from users
where (username='bob' and password='') or true
che è logicamente uguale a
select id, username
from users
where true
che è logicamente uguale a
select id, username
from users
Pertanto, verranno restituiti tutti gli utenti nel database e verrà registrato come il primo nell'elenco, che di solito è l'amministratore.
È anche possibile utilizzare SQL injection per leggere tutti i dati dal database. Immettendo il nome utente come segue (sintassi di SQL Server) verranno elencati i nomi delle tabelle definite dall'utente
' union select -1, name, from sysobjects where xtype = 'U' order by id --
perché questo produce
select id, username
from users
where username = ''
union
select -1, name
from sysobjects
where xtype = 'U'
order by id asc
perché i nostri dati iniettati hanno un id
di -1 e stiamo ordinando i dati per id, la prima riga restituita dal database sarà la nostra selezione nella tabella sysobjects
. Quindi il nostro " username
" visualizzato sarà ora il nome della prima tabella creata dall'utente nel database. Tecniche simili possono essere ripetute per leggere tutti i dati di ogni colonna di ogni riga di ogni tabella accessibile. Si noti che questo può ancora essere fatto anche quando la funzione attaccata non produce affatto output!
Alcune combinazioni di librerie di database di linguaggio di programmazione e DBMS consentono anche stacking di query . Questa è una tecnica in cui alla fine viene aggiunto un comando SQL completamente nuovo. Il database eseguirà entrambe le query. Nome utente:
'; delete from users --
produce
select id, username
from users
where username='';
delete from users
Ora la tua applicazione non ha utenti (e richiede l'iniezione SQL per accedere). Vedi fumetto XKCD obbligatorio .
Vedi questo SQL cheat sheet se sei interessato a più tecniche comunemente usate dagli aggressori e vulnerabilità tester.
Quindi come evito questo?
In realtà, in molti scenari comuni, è così facile. Prepared statements
dati separati dal codice e non consentono di trattare i parametri come codice SQL. Ricodifica semplicemente la query per utilizzare istruzioni preparate e associare i singoli parametri ai segnaposto.
in pseudocode:
username = getPostData( "username" );
password = getPostData( "password" );
sql = "select id, username from users where username=? and password=?";
query = prepareStatement( sql );
query.setParameter( 0, username );
query.setParameter( 1, password );
result = executePreparedStatement( query );
Come sempre questa non è l'intera storia ...
Non dimenticare di difendere in modo approfondito e fai sempre anche la convalida dell'input, come faresti sempre (dovresti). Le clausole WHERE richiedono maggiore attenzione in quanto caratteri speciali come %
potrebbero non essere ricercati. Prestare particolare attenzione quando si passano dati utente come argomenti alle funzioni del database e si deve essere consapevoli di come possano essere abusati. Se hai memorizzato le procedure che generano query dinamiche potresti aver bisogno di ulteriore protezione all'interno delle procedure stesse.
SQL Injection è una tecnica che utilizza i comandi SQL validi per manomettere, eliminare o iniettare dati in un database back-end direttamente attraverso i punti deboli nella convalida dell'input del codice a un'applicazione web che chiama quel database.
È uno dei OWASP Top Ten delle rotte di attacco più comuni in quanto è molto semplice sfruttare.
Può essere utilizzato per compromettere interi database di dati dei clienti, dati di carte di credito, registrazioni finanziarie ecc. o per ottenere una copia di questi dati. Generalmente un impatto abbastanza importante!
La cosa buona è che è molto facile mitigare tramite Input Validation - la maggior parte dei framework fornisce moduli per farlo.
Leggi altre domande sui tag sql-injection terminology