Iniezione SQL
SQL Injection
SQL injection è una tecnica di iniezione di codice che potrebbe distruggere il database.
L'SQL injection è una delle tecniche di web hacking più comuni.
SQL injection è il posizionamento di codice dannoso nelle istruzioni SQL, tramite l'input di una pagina web.
SQL nelle pagine Web
L'iniezione SQL di solito si verifica quando chiedi a un utente un input, come il suo nome utente/id utente, e invece di un nome/id, l'utente ti fornisce un'istruzione SQL che eseguirai inconsapevolmente sul tuo database.
Guarda il seguente esempio che crea
SELECT
un'istruzione aggiungendo una variabile (txtUserId) a una stringa di selezione. La variabile viene recuperata dall'input dell'utente (getRequestString):
Esempio
txtUserId = getRequestString("UserId");
txtSQL = "SELECT *
FROM Users WHERE UserId = " + txtUserId;
Il resto di questo capitolo descrive i potenziali pericoli dell'utilizzo dell'input dell'utente nelle istruzioni SQL.
SQL injection Basato su 1=1 è sempre vero
Guarda di nuovo l'esempio sopra. Lo scopo originale del codice era creare un'istruzione SQL per selezionare un utente, con un determinato ID utente.
Se non c'è nulla che impedisca a un utente di inserire un input "sbagliato", l'utente può inserire un input "intelligente" come questo:
ID utente:
Quindi, l'istruzione SQL sarà simile a questa:
SELECT * FROM Users WHERE UserId = 105 OR 1=1;
L'SQL sopra è valido e restituirà TUTTE le righe dalla tabella "Utenti", poiché OR 1=1 è sempre TRUE.
L'esempio sopra sembra pericoloso? Cosa succede se la tabella "Utenti" contiene nomi e password?
L'istruzione SQL sopra è più o meno la stessa di questa:
SELECT UserId, Name, Password
FROM Users WHERE UserId = 105 or 1=1;
Un hacker potrebbe ottenere l'accesso a tutti i nomi utente e le password in un database, semplicemente inserendo 105 OPPURE 1=1 nel campo di input.
SQL injection Basato su ""="" è sempre vero
Ecco un esempio di login utente su un sito web:
Nome utente:
Parola d'ordine:
Esempio
uName = getRequestString("username");
uPass = getRequestString("userpassword");
sql = 'SELECT * FROM Users WHERE Name ="' + uName + '" AND Pass ="' + uPass +
'"'
Risultato
SELECT * FROM Users WHERE Name ="John Doe" AND Pass ="myPass"
Un hacker potrebbe ottenere l'accesso ai nomi utente e alle password in un database semplicemente inserendo " OR ""=" nella casella di testo del nome utente o della password:
Nome utente:
Parola d'ordine:
Il codice sul server creerà un'istruzione SQL valida come questa:
Risultato
SELECT * FROM Users WHERE Name ="" or ""="" AND Pass ="" or ""=""
L'SQL sopra è valido e restituirà tutte le righe dalla tabella "Utenti", poiché OR ""="" è sempre TRUE.
Iniezione SQL basata su istruzioni SQL in batch
La maggior parte dei database supporta l'istruzione SQL in batch.
Un batch di istruzioni SQL è un gruppo di due o più istruzioni SQL, separate da punti e virgola.
L'istruzione SQL seguente restituirà tutte le righe della tabella "Utenti", quindi eliminerà la tabella "Fornitori".
Esempio
SELECT * FROM Users; DROP TABLE Suppliers
Guarda il seguente esempio:
Esempio
txtUserId = getRequestString("UserId");
txtSQL = "SELECT *
FROM Users WHERE UserId = " + txtUserId;
E il seguente input:
ID utente:
L'istruzione SQL valida sarebbe simile a questa:
Risultato
SELECT * FROM Users WHERE
UserId = 105; DROP TABLE Suppliers;
Utilizzare i parametri SQL per la protezione
Per proteggere un sito Web dall'iniezione SQL, è possibile utilizzare i parametri SQL.
I parametri SQL sono valori che vengono aggiunti a una query SQL al momento dell'esecuzione, in modo controllato.
Esempio di rasoio ASP.NET
txtUserId = getRequestString("UserId");
txtSQL = "SELECT *
FROM Users WHERE UserId = @0";
db.Execute(txtSQL,txtUserId);
Si noti che i parametri sono rappresentati nell'istruzione SQL da un indicatore @.
Il motore SQL controlla ogni parametro per assicurarsi che sia corretto per la sua colonna e che sia trattato letteralmente e non come parte dell'SQL da eseguire.
Un altro esempio
txtNam = getRequestString("CustomerName");
txtAdd = getRequestString("Address");
txtCit = getRequestString("City");
txtSQL = "INSERT INTO Customers (CustomerName,Address,City) Values(@0,@1,@2)";
db.Execute(txtSQL,txtNam,txtAdd,txtCit);
Esempi
Gli esempi seguenti mostrano come creare query parametrizzate in alcuni linguaggi Web comuni.
SELEZIONA DICHIARAZIONE IN ASP.NET:
txtUserId = getRequestString("UserId");
sql = "SELECT * FROM Customers WHERE CustomerId = @0";
command = new SqlCommand(sql);
command.Parameters.AddWithValue("@0",txtUserId);
command.ExecuteReader();
INSERIRE IN RENDICONTO IN ASP.NET:
txtNam = getRequestString("CustomerName");
txtAdd = getRequestString("Address");
txtCit = getRequestString("City");
txtSQL = "INSERT INTO Customers (CustomerName,Address,City) Values(@0,@1,@2)";
command = new SqlCommand(txtSQL);
command.Parameters.AddWithValue("@0",txtNam);
command.Parameters.AddWithValue("@1",txtAdd);
command.Parameters.AddWithValue("@2",txtCit);
command.ExecuteNonQuery();
INSERIRE NELLA DICHIARAZIONE IN PHP:
$stmt = $dbh->prepare("INSERT INTO Customers (CustomerName,Address,City)
VALUES (:nam, :add, :cit)");
$stmt->bindParam(':nam', $txtNam);
$stmt->bindParam(':add', $txtAdd);
$stmt->bindParam(':cit', $txtCit);
$stmt->execute();