Gli ultimi tutorial di sviluppo web
 

SQL Iniezione


Un'iniezione SQL può distruggere la vostra base di dati.


SQL nelle pagine Web

Nei capitoli precedenti, avete imparato a recuperare i dati del database (e aggiornare), utilizzando SQL.

Quando SQL viene utilizzato per visualizzare i dati in una pagina web, è comune per permettere di ingresso gli utenti di Internet i propri valori di ricerca.

Dal momento che le istruzioni SQL sono solo testo, è facile, con un piccolo pezzo di codice di computer, per modificare dinamicamente le istruzioni SQL per fornire all'utente i dati selezionati:

codice del server

txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = " + txtUserId;

L'esempio di cui sopra, crea un'istruzione select con l'aggiunta di una variabile (txtUserId) in una stringa di selezione. La variabile prelevato dalla input dell'utente (Request) alla pagina.

Il resto di questo capitolo descrive i potenziali pericoli di utilizzare l'input dell'utente in istruzioni SQL.


SQL Injection

SQL injection è una tecnica in cui utenti malintenzionati possono iniettare comandi SQL in un'istruzione SQL, tramite l'ingresso pagina web.

comandi SQL iniettati possono alterare istruzione SQL e compromettere la sicurezza di un'applicazione web.


SQL Injection Sulla base 1 = 1 è sempre vero

Guardate l'esempio di cui sopra, ancora una volta.

Diciamo che lo scopo originale del codice era quello di creare un'istruzione SQL per selezionare un utente con un dato id utente.

Se non vi è nulla per impedire a un utente di entrare "wrong" di ingresso, l'utente può inserire un po 'di "smart" di ingresso in questo modo:

ID utente:

Risultato Server

SELECT * FROM Users WHERE UserId = 105 or 1=1

L'SQL di cui sopra è valido. Si restituirà tutte le righe della tabella degli utenti, dal momento che dove 1 = 1 è sempre vero.

Fa l'esempio di cui sopra sembrano pericoloso? Che cosa se la tabella Utenti contiene i nomi e le password?

L'istruzione SQL di cui sopra è molto simile a quello presente:

SELECT UserId, Name, Password FROM Users WHERE UserId = 105 or 1=1

Un hacker intelligente potrebbe ottenere l'accesso a tutti i nomi utente e le password in un database, semplicemente inserendo 105 o 1 = 1 nella casella di input.


SQL Injection Sulla base di ""="" è sempre vero

Qui è una costruzione comune, utilizzato per verificare il login utente a un sito web:

Nome utente:

Parola d'ordine:

codice del server

uName = getRequestString("UserName");
uPass = getRequestString("UserPass");

sql = "SELECT * FROM Users WHERE Name ='" + uName + "' AND Pass ='" + uPass + "'"

Un hacker intelligente potrebbe ottenere l'accesso a nomi utente e password in un database, semplicemente inserendo "o ""=" nel nome utente o la password casella di testo.

Il codice sul server creerà un'istruzione SQL valida in questo modo:

Risultato

SELECT * FROM Users WHERE Name ="" or ""="" AND Pass ="" or ""=""

Il SQL risultato è valido. Si restituirà tutte le righe della tabella degli utenti, dal momento che dove "" = "" è sempre vero.


SQL Injection Sulla base di istruzioni SQL batch

La maggior parte dei database supportano istruzione SQL in batch, separati da virgola.

Esempio

SELECT * FROM Users; DROP TABLE Suppliers

Il SQL sopra restituirà tutte le righe della tabella Utenti, e quindi eliminare la tabella denominata Fornitori.

Se avessimo il seguente codice del server:

codice del server

txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = " + txtUserId;

E il seguente comando:

ID utente:

Il codice sul server creerebbe un'istruzione SQL valida in questo modo:

Risultato

SELECT * FROM Users WHERE UserId = 105; DROP TABLE Suppliers

I parametri per la protezione

Alcuni sviluppatori web utilizzano una "blacklist" di parole o caratteri da cercare nel ingresso SQL, per prevenire attacchi di SQL injection.

Questa non è una buona idea. Molte di queste parole (come cancellare o cadere) e personaggi (come il punto e virgola e virgolette), sono utilizzati nel linguaggio comune, e dovrebbe essere permesso in molti tipi di input.

(In realtà dovrebbe essere perfettamente legale per inserire un'istruzione SQL in un campo di database.)

L'unico modo dimostrato di proteggere un sito web da attacchi di SQL injection, è quello di utilizzare parametri SQL.

parametri SQL sono valori che vengono aggiunti a una query SQL in fase di esecuzione, in modo controllato.

ASP.NET Razor Esempio

txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = @0";
db.Execute(txtSQL,txtUserId);

Si noti che i parametri sono rappresentate nell'istruzione SQL da un indicatore @.

Il motore SQL controlla ogni parametro per assicurarsi che sia corretta per la colonna e sono trattati letteralmente, e non come da eseguire parte del SQL.

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);

Hai appena imparato ad evitare SQL injection. Uno dei principali vulnerabilità dei siti Web.


Esempi

Gli esempi che seguono mostrano come costruire query con parametri in alcuni linguaggi web più comuni.

SELECT in ASP.NET:

txtUserId = getRequestString("UserId");
sql = "SELECT * FROM Customers WHERE CustomerId = @0";
command = new SqlCommand(sql);
command.Parameters.AddWithValue("@0",txtUserID);
command.ExecuteReader();

INSERT INTO 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();

INSERT INTO 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();