Injecție SQL

Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de versiunea revizuită pe 19 decembrie 2021; verificările necesită 9 modificări .

Injecția SQL ( în engleză  SQL injection /SQLi ) este una dintre cele mai comune moduri de a pirata site-uri și programe care funcționează cu baze de date , bazată pe introducerea unui cod SQL arbitrar într-o interogare .

Injecția SQL, în funcție de tipul de SGBD utilizat și de condițiile de injectare, poate permite unui atacator să execute o interogare arbitrară în baza de date ( de exemplu, să citească conținutul oricăror tabele , să șterge, să modifice sau să adauge date ), să obțină capacitatea să citească și/sau să scrie fișiere locale și să execute comenzi arbitrare pe serverul atacat.

Un atac de tip injecție SQL poate fi posibil din cauza procesării incorecte a datelor de intrare utilizate în interogările SQL.

Un dezvoltator de aplicații de bază de date ar trebui să fie conștient de astfel de vulnerabilități și să ia măsuri pentru a contracara injecția SQL.

Tipuri de atacuri precum injecția SQL

Există trei clase principale de atacuri bazate pe injecția SQL:

Principiul atacului prin injecție SQL

Să presupunem că software- ul serverului , după ce a primit parametrul de intrare id, îl folosește pentru a crea o interogare SQL. Luați în considerare următorul script PHP :

$id = $_CERERE [ 'id' ]; $res = mysqli_query ( "SELECT * FROM news WHERE id_news = " . $id );

Dacă un parametru id egal cu 5 este transmis către server (de exemplu: http://example.org/script.php?id=5 ), atunci următoarea interogare SQL va fi executată:

SELECTAȚI * DIN știri WHERE id_news = 5

Dar dacă un atacator trece șirul -1 SAU 1=1 ca parametru id (de exemplu, astfel: http://example.org/script.php?id=-1+OR+1=1 ), atunci cererea va fi executata:

SELECTAȚI * DIN știri WHERE id_news = - 1 SAU 1 = 1

Astfel, modificarea parametrilor de intrare prin adăugarea de constructe ale limbajului SQL provoacă o modificare a logicii de execuție a interogării SQL (în acest exemplu, în loc de știri cu un anumit identificator, toate știrile din baza de date vor fi selectate, deoarece expresia 1=1 este întotdeauna adevărată - calculele sunt efectuate folosind cel mai scurt contur din diagramă ).

Injectare în parametrii șirului

Să presupunem că software-ul serverului, după ce a primit o solicitare de căutare a datelor în știri cu parametrul search_text, îl folosește în următoarea interogare SQL (aici parametrii sunt evadați cu ghilimele):

$text_căutare = $_REQUEST [ 'text_căutare' ]; $res = mysqli_query ( "SELECT id_news, news_date, news_caption, news_text, news_id_author FROM news WHERE news_caption LIKE('% $search_text %')" );

Făcând o interogare de genul http://example.org/script.php?search_text=Test , obținem următoarea interogare SQL care urmează să fie executată:

SELECTează id_news , news_date , news_caption , news_text , news_id_author FROM news WHERE news_caption LIKE ( '%Test%' )

Dar prin încorporarea unui caracter de ghilimele (care este folosit în interogare) în parametrul search_text, putem schimba drastic comportamentul interogării SQL. De exemplu, prin trecerea valorii ' )+and+(news_id_author='1 ) ca parametru search_text , vom apela interogarea care urmează să fie executată:

SELECTează id_news , news_date , news_caption , news_text , news_id_author FROM news WHERE news_caption LIKE ( '%' ) și ( news_id_author = '1%' )

Folosind UNION

Limbajul SQL vă permite să combinați rezultatele mai multor interogări folosind operatorul UNION . Acest lucru oferă unui atacator posibilitatea de a obține acces neautorizat la date.

Să luăm în considerare scriptul de afișare a știrilor ( identificatorul știrilor de afișat este trecut în parametrul id ):

$res = mysqli_query ( "SELECT id_news, header, body, author FROM news WHERE id_news = " . $_REQUEST [ 'id' ]);

Dacă un atacator trece -1 UNION SELECT 4 nume de utilizator, parolă,1 FROM admin ca parametru id , aceasta va determina executarea interogării SQL

SELECT id_news , header , body , autor FROM stiri WHERE id_news = - 1 UNION SELECT 1 , nume de utilizator , parola , 1 FROM admin

Deoarece știrile cu identificatorul -1 cu siguranță nu există, nu vor fi selectate înregistrări din tabelul de știri, dar rezultatul va include înregistrări care au fost selectate ilegal din tabelul de administrare ca urmare a injecției SQL.

Folosind UNION + group_concat()

În unele cazuri, un hacker poate ataca, dar nu poate vedea mai mult de o coloană. În cazul MySQL , un atacator poate folosi funcția:

group_concat ( col , simbol , col )

care combină mai multe coloane într-una singură. De exemplu, pentru exemplul dat mai sus, apelul funcției ar fi:

- 1 UNION SELECT group_concat ( nume utilizator , 0 x3a , parola ) FROM admin

Coada interogării evadează

Adesea, interogarea SQL afectată de această vulnerabilitate are o structură care face dificilă sau imposibilă utilizarea uniunii. De exemplu script:

$res = mysqli_query ( "SELECT AUTOR FROM news WHERE id=" . $_REQUEST [ 'id' ] . " AND autor LIKE ('a%')" );

afișează numele autorului știrilor după identificatorul ID transmis doar dacă numele începe cu litera a, iar injectarea codului folosind operatorul UNION este dificilă.

În astfel de cazuri, atacatorii folosesc metoda de evadare a unei părți a cererii folosind caractere de comentariu ( /* sau -- în funcție de tipul de DBMS).

În acest exemplu, un atacator poate transmite parametrul id cu valoarea -1 UNION SELECT password FROM admin/* către script , executând astfel interogarea

SELECTAȚI autorul DIN știri WHERE id =- 1 UNION SELECTARE parolă FROM admin /* ȘI autor LIKE ('a%')

în care o parte a interogării ( ȘI autorul LIKE ('a%') ) este marcată ca comentariu și nu afectează execuția.

Împărțirea unei interogări SQL

Simbolul ; este folosit pentru a separa comenzile în limbajul SQL ; ( punct și virgulă ) prin încorporarea acestui caracter într-o interogare, un atacator este capabil să execute mai multe comenzi într-o singură interogare, cu toate acestea, nu toate dialectele SQL acceptă această capacitate.

De exemplu, dacă în parametrii scriptului

$id = $_CERERE [ 'id' ]; $res = mysqli_query ( "SELECT * FROM news WHERE id_news = $id " );

atacatorul trece un construct care conține punct și virgulă, de exemplu 12;INSERT INTO admin (nume de utilizator, parolă) VALUES ('HaCkEr', 'foo'); apoi 2 comenzi vor fi executate într-o singură interogare

SELECT * FROM news WHERE id_news = 12 ; INSERT INTO admin ( nume utilizator , parola ) VALUES ( 'HaCkEr' , 'foo' );

și o înregistrare neautorizată a Hackerului va fi adăugată la tabelul de administrare.

Tehnici de atac prin injecție SQL

Găsirea scripturilor vulnerabile la atac

În această etapă, atacatorul examinează comportamentul scripturilor de server atunci când manipulează parametrii de intrare pentru a detecta comportamentul lor anormal. Manipularea are loc cu toți parametrii posibili:

  • Datele au trecut prin metodele POST și GET
  • Valori [HTTP Cookie].
  • HTTP_REFERER (pentru scripturi)
  • AUTH_USER și AUTH_PASSWORD (când utilizați autentificarea)

De regulă, manipularea se reduce la înlocuirea unui singur ghilimeleu (mai rar dublu sau înapoi) în parametrii caracterului.

Comportamentul anormal este orice comportament în care paginile preluate înainte și după înlocuirea citatelor sunt diferite (și nu afișează pagina cu formatul parametrului nevalid).

Cele mai comune exemple de comportament anormal sunt:

  • sunt afișate diverse mesaje de eroare;
  • la solicitarea datelor (de exemplu, știri sau o listă de produse), datele solicitate nu sunt afișate deloc, deși pagina este afișată

etc. Trebuie avut în vedere că există cazuri când mesajele de eroare, din cauza specificului markupului paginii, nu sunt vizibile în browser, deși sunt prezente în codul HTML al acestuia.

Proiecta Comentând restul rândului Obțineți versiunea Concatenarea șirurilor
MySQL -- ..., /* ..., sau# ... version() concat (string1, string2)
MS SQL -- ... @@version string1 + string2
Oracol -- ...sau/* ... select banner
from v$version
string1 || string2
sauconcat (string1, string2)
MS Access Injectarea unui octet NULL într-o solicitare:%00...
PostgreSQL -- ... SELECT version() string1 || string2,CONCAT('a','b')
Sybase -- ... @@version string1 + string2
IBM DB2 -- ... select versionnumber from sysibm.sysversions string1 || string2saustring1 concat string2
Ingres -- ... dbmsinfo('_version') string1 || string2

Protecție împotriva atacurilor precum injecția SQL

Pentru a vă proteja împotriva acestui tip de atac, este necesar să filtrați cu atenție parametrii de intrare, ale căror valori vor fi folosite pentru a construi interogarea SQL.

Filtrarea parametrilor șirului

Să presupunem că codul care generează cererea (în limbajul de programare Pascal ) arată astfel:

declarație := 'SELECT * FROM users WHERE nume = "' + userName + '";' ;

Pentru a face injectarea de cod (închiderea unui șir care începe cu un citat cu un alt citat înainte de a se termina cu citatul de închidere curent pentru a împărți interogarea în două părți) a fost imposibil, pentru unele SGBD , inclusiv MySQL , este necesar să citați toți parametrii șirului . . În parametrul propriu-zis, înlocuiți ghilimelele cu \”, apostroful cu \’, bara oblică inversă cu \\ (aceasta se numește „ scăpare de caractere speciale ”). Acest lucru se poate face cu următorul cod:

declarație := 'SELECT * FROM users WHERE nume = ' + QuoteParam ( nume utilizator ) + ';' ; funcția QuoteParam ( s : șir ) : șir ; { la intrare - un șir; ieșirea este un șir între ghilimele și cu caractere speciale înlocuite } var i : integer ; dest : șir _ începe Dest := '"' ; pentru i := 1 la lungimea ( s ) face case s [ i ] of ' '' ' : Dest := Dest + '\ '' ' ; '"' : Dest := Dest + '\"' ; '\' : Dest := Dest + '\\' ; else Dest := Dest + s [ i ] ; final ; QuoteParam := Dest + '"' ; sfârşitul ;

Pentru PHP, filtrarea poate fi astfel:

$query = "SELECT * FROM users WHERE user='" . mysqli_real_escape_string ( $user ) . "';" ;

Filtrarea parametrilor întregi

Să luăm o altă cerere:

declarație := 'SELECT * FROM users WHERE id = ' + id + ';' ;

În acest caz, câmpul idare un tip numeric și cel mai adesea nu este citat. Prin urmare, „citarea” și înlocuirea caracterelor speciale cu secvențe de evacuare nu funcționează. În acest caz, verificarea tipului ajută; dacă variabila idnu este un număr, interogarea nu ar trebui să ruleze deloc.

De exemplu, în Delphi , următorul cod ajută la contracararea unor astfel de injecții:

if TryStrToInt ( id , id_int ) then statement := Format ( 'SELECT * FROM users WHERE id =%0:d;' , [ id_int ]) ;

Pentru PHP, această metodă ar arăta astfel:

$query = 'SELECT * FROM utilizatorii WHERE id = ' . ( int ) $id ;

Trunchierea parametrilor de intrare

Pentru a face modificări în logica executării unei interogări SQL, este necesară injectarea de șiruri suficient de lungi. Deci, lungimea minimă a șirului încorporat în exemplele de mai sus este de 8 caractere (“ 1 SAU 1=1 ”). Dacă lungimea maximă a unei valori valide a parametrului este mică, atunci una dintre metodele de protecție poate fi trunchierea maximă a valorilor parametrilor de intrare.

De exemplu, dacă se știe că câmpul iddin exemplele de mai sus poate lua valori nu mai mult de 9999, puteți „taia caracterele suplimentare”, lăsând nu mai mult de patru:

declarație := 'SELECT * FROM users WHERE id = ' + LeftStr ( id , 4 ) + ';' ;

Folosind interogări parametrizate

Multe servere de baze de date acceptă capacitatea de a trimite interogări parametrizate (instrucțiuni pregătite). În acest caz, parametrii de origine externă sunt trimiși către server separat de cererea în sine, sau sunt evadați automat de biblioteca client. Pentru aceasta se folosesc

  • în Delphi  - proprietate TQuery.Params;

De exemplu

var sql , param : șir begin sql := 'select :text as value from dual' ; param := 'alfa' ; Interogarea 1 . Sql . Text : = sql Interogarea 1 . ParamByName ( 'text' ) . AsString := param ; Interogarea 1 . deschis ; ShowMessage ( Interogare1 [ 'valoare' ]) ; sfârşitul ;
  • în Perl  - prin DBI::quotesau DBI::prepare;
  • in Java  , prin clasa PreparedStatement;
  • în C#  - proprietate SqlCommand.Parameters;
  • în PHP  - MySQLi (când lucrați cu MySQL ), PDO.

Vezi și

Link -uri