Ultimele tutoriale de dezvoltare web
 

SQL Injecţie


O injecție SQL poate distruge baza de date.


SQL în paginile web

În capitolele anterioare, ați învățat să preluați (and update) date de baze de date, folosind SQL.

Atunci când SQL este folosit pentru a afișa date pe o pagină web, este comun pentru a permite utilizatorilor de web de intrare propriile lor valori de căutare.

Deoarece declarațiile SQL sunt doar text, este ușor, cu o mică bucată de cod de computer, pentru a modifica dinamic declarații SQL pentru a furniza utilizatorului de date selectate:

Cod server

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

Exemplul de mai sus, creează o declarație select prin adăugarea unei variabile (txtUserId) la un șir select. Variabila este preluată din datele introduse de utilizator (Request) la pagina.

Restul acestui capitol descrie pericolele potențiale folosind datele introduse de utilizator în declarațiile SQL.


SQL Injection

injecție SQL este o tehnică prin care utilizatorii rău intenționate pot injecta comenzi SQL într-o instrucțiune SQL, prin intermediul paginii web de intrare.

Comenzile SQL injectati pot modifica declarația SQL și compromite securitatea unei aplicatii web.


SQL Injection Bazat pe 1 = 1 este întotdeauna adevărat

Uită-te la exemplul de mai sus, o mai mult timp.

Să presupunem că scopul inițial al codului a fost de a crea o instrucțiune SQL pentru a selecta un utilizator cu un anumit ID de utilizator.

Dacă nu există nimic pentru a împiedica un utilizator să intre "wrong" de intrare, utilizatorul poate introduce unele "smart" de intrare astfel:

Numele de utilizator:

Server Rezultat

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

SQL de mai sus este valabilă. Acesta va returna toate rândurile utilizatorilor de masă, deoarece unde 1 = 1 este întotdeauna adevărat.

Are exemplul de mai sus se pare periculos? Ce se întâmplă dacă tabelul Users conține nume și parole?

Instrucțiunea SQL de mai sus este mult la fel ca aceasta:

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

Un hacker inteligent ar putea avea acces la toate numele de utilizator și parolele într-o bază de date prin simpla introducere 105 sau 1 = 1 în caseta de intrare.


SQL Injection Bazat pe ""="" este întotdeauna adevărat

Aici este o construcție comună, folosit pentru a verifica logare utilizator la un site web:

Nume de utilizator:

Parola:

Cod server

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

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

Un hacker inteligent ar putea avea acces la nume de utilizator și parolele într - o bază de date prin simpla introducere „sau ""=" în numele de utilizator sau parola caseta de text.

Codul la serverul va crea o instrucțiune validă SQL astfel:

Rezultat

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

Rezultatul SQL este valid. Acesta va returna toate rândurile utilizatorilor de masă, din moment unde „“ = „“ este întotdeauna adevărat.


SQL Injection pe baza declarațiilor SQL batch

Cele mai multe baze de date suporta instrucțiuni SQL în etape, separate prin virgulă.

Exemplu

SELECT * FROM Users; DROP TABLE Suppliers

SQL de mai sus va returna toate rândurile din tabelul de utilizatori, și apoi ștergeți tabelul numit Furnizori.

Dacă am avea următorul cod de server:

Cod server

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

Iar următoarea intrare:

Numele de utilizator:

Codul la server ar crea o instrucțiune validă SQL astfel:

Rezultat

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

Parametri pentru Protecția

Unii dezvoltatori web utilizează o "blacklist" de cuvinte sau caractere pentru a căuta în SQL de intrare, pentru a preveni atacurile SQL injection.

Aceasta nu este o idee foarte bună. Multe dintre aceste cuvinte (like delete or drop) și caractere (like semicolons and quotation marks) , sunt utilizate într -un limbaj comun, și ar trebui să fie permisă în mai multe tipuri de intrare.

(De fapt, ar trebui să fie perfect legal de a introduce o instrucțiune SQL într-un domeniu de baze de date.)

Singura modalitate de dovedit a proteja un site web de la atacuri SQL injection, este de a utiliza parametrii SQL.

Parametrii SQL sunt valori care sunt adăugate la o interogare SQL la timpul de execuție, într-un mod controlat.

ASP.NET Razor Exemplu

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

Rețineți că parametrii sunt reprezentați în instrucțiunea SQL cu un marker @.

Motorul SQL verifică fiecare parametru pentru a se asigura că este corect pentru coloana sa și sunt tratate literal, și nu ca parte a SQL care urmează să fie executat.

Alt exemplu

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

Tocmai ați învățat pentru a evita SQL injection. Una dintre primele vulnerabilitati site-ului.


Exemple

Următoarele exemple arată cum să construiască interogări parametrizate în unele limbi web comune.

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 în 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 în 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();