logo

Injecție SQL

SQL Injection este o defecțiune de securitate în aplicațiile web în care atacatorii introduc cod SQL dăunător prin introducerea utilizatorului. Acest lucru le poate permite să acceseze conținutul bazei de date de modificare a datelor sensibile sau chiar să preia controlul asupra sistemului. Este important să știți despre SQL Injection pentru a menține aplicațiile web în siguranță.

SQL Injection (SQLi) este o vulnerabilitate de securitate care apare atunci când un atacator poate manipula interogările bazei de date ale unei aplicații web prin inserarea de cod SQL rău intenționat în câmpurile de introducere a utilizatorului. Aceste interogări injectate pot manipula baza de date subiacentă pentru a prelua date modificate sau șterse. În unele cazuri, atacatorii pot chiar escalada privilegiile obținând control deplin asupra bazei de date sau serverului.



injecție sql' title=

Exemplu real:

În 2019, Capital One Data Breach a avut loc din cauza unei aplicații web configurate greșit care a permis unui atacator să exploateze o vulnerabilitate de injectare SQL. Acest lucru a dus la scurgerea de date personale a peste 100 de milioane de clienți, inclusiv nume, adrese și scoruri de credit.

Nivel de securitate SQL Injection

DVWA oferă patru niveluri de securitate pentru SQL Injection pentru a ajuta cursanții să vadă modul în care diferitele protecții afectează atacurile:



1. Securitate scăzută

Aplicația vă preia intrarea și o pune direct în interogarea SQL, fără filtrare.

$id = $_GET['id'];$query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';';
  • Intrând ': Rupe interogarea și face ca baza de date să arunce o eroare care dezvăluie că este vulnerabilă.
  • Intrând 1' OR '1'='1: Face ca interogarea să fie întotdeauna adevărată, astfel încât toți utilizatorii să fie returnați.
  • Intrând 1' UNION SELECT user password FROM users--: Se alătură unei alte interogări pentru a prelua date ascunse, cum ar fi numele de utilizator și parolele.

2. Securitate medie

Aplicația aplică igienizarea de bază a intrărilor folosind funcții precumaddslashes()a scăpa'.

$id = addslashes($_GET['id']);$query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';';

Cum poate fi un atac:



Un simplu'injecția nu va mai funcționa (pentru că devine').

Dar atacatorii pot încă ocoli folosind injecția numerică (deoarece numerele nu au nevoie de ghilimele).
Exemplu:

t ff
1 OR 1=1

Acest lucru returnează în continuare toate înregistrările.

3. Securitate ridicată

Aplicația folosește instrucțiuni pregătite (interogări parametrizate) pentru a gestiona în siguranță intrarea utilizatorului.

$stmt = $pdo->prepare('SELECT first_name last_name FROM users WHERE user_id = ?');$stmt->execute([$id]);

Atac:

Incercari de genul' OR 1=1sauUNION SELECTnu mai functioneaza.

Interogarea tratează toate intrările ca date, nu ca cod SQL.

Tipuri de injecție SQL

Există diferite tipuri de injecție SQL

1. Injectare SQL bazată pe erori

Injecția SQL bazată pe erori este un tip de injecție SQL în bandă în care un atacator determină în mod intenționat baza de date să genereze un mesaj de eroare. Atacatorul analizează apoi acest mesaj de eroare pentru a obține informații valoroase despre structura bazei de date, cum ar fi numele tabelelor și numele coloanelor, care pot fi folosite pentru a crea atacuri mai precise.

Cum funcționează

Acest atac vizează aplicațiile care dezvăluie erori brute ale bazei de date în loc să arate mesaje generice. Prin injectarea unei intrări rău intenționate care rupe sintaxa SQL, atacatorii declanșează aceste erori și obțin indicii valoroase despre structura bazei de date.

spring initializr
  1. Identificați o intrare vulnerabilă: Atacatorul găsește un câmp de introducere, cum ar fi o bară de căutare sau un parametru URL, care interacționează direct cu baza de date fără o igienizare adecvată a intrărilor.
  2. Injectați o sarcină utilă rău intenționată: Atacatorul injectează un caracter special (cum ar fi un singur ghilimele).') sau o funcție despre care se știe că cauzează o eroare în baza de date.
  3. Analizați eroarea: Baza de date care nu poate procesa interogarea malformată returnează un mesaj de eroare detaliat. Acest mesaj poate dezvălui informații cruciale, cum ar fi:
    • Sistemul de baze de date (de exemplu, MySQL Oracle SQL Server).
    • Versiunea bazei de date.
    • Se execută interogarea SQL completă.
    • Erori de sintaxă specifice care pot fi folosite pentru a înțelege numele tabelelor sau coloanelor.
  4. Rafinați atacul: Folosind informațiile culese din mesajul de eroare, atacatorul își poate rafina sarcina utilă pentru a extrage mai multe date, cum ar fi nume de utilizator și parole.

Exemplu:

Pasul 1: Configurați-vă mediul

  • Lansați DVWA. Este de obicei accesat navigând la o adresă URL, cum ar fihttp://localhost/dvwaîn browserul dvs.
fişier' loading='lazy' title=
  • Conectați-vă la DVWA cu acreditările implicite:admin/password.
fişier' loading='lazy' title=
  • Accesați fila Securitate DVWA și setați nivelul de securitate la scăzut. Acest lucru va asigura că vulnerabilitățile sunt ușor de exploatat.
fişier' loading='lazy' title=

Pasul 2: Identificați vulnerabilitatea

Pagina SQL Injection are o casetă de introducere simplă în care puteți introduce un ID de utilizator. Interogarea backend este probabil ceva de genulSELECT * FROM users WHERE id = 'user_input'

  • Introduceți un ID valid like1în caseta de introducere și faceți clic pe „Trimite”. Ar trebui să vedeți detaliile utilizatorului cu ID 1.
fişier' loading='lazy' title=

Sursa de injectare SQL

PHP
 $id = $_REQUEST[ 'id' ]; switch ($_DVWA['SQLI_DB']) { case MYSQL: // Check database $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; $result = mysqli_query($GLOBALS['___mysqli_ston'] $query ) or die( '
' . ((is_object($GLOBALS['___mysqli_ston'])) ? mysqli_error($GLOBALS['___mysqli_ston']) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
'
); // Get results while( $row = mysqli_fetch_assoc( $result ) ) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo '
ID: {$id}  
First name:
{$first}
Surname:
{$last}
'
; } mysqli_close($GLOBALS['___mysqli_ston']); break; case SQLITE: global $sqlite_db_connection; #$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']); #$sqlite_db_connection->enableExceptions(true); $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; #print $query; try { $results = $sqlite_db_connection->query($query); } catch (Exception $e) { echo 'Caught exception: ' . $e->getMessage(); exit(); } if ($results) { while ($row = $results->fetchArray()) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo '
ID: {$id}  
First name:
{$first}
Surname:
{$last}
'
; } } else { echo 'Error in fetch '.$sqlite_db->lastErrorMsg(); } break; } } ode ?>
  • Acum încercați să întrerupeți interogarea. Introduceți un singur citat'în caseta de introducere și trimiteți.
fişier' loading='lazy' title=

Interogarea devine:

SELECT * FROM users WHERE id = ''';

Aici baza de date vede o cotație suplimentară și nu știe cum să completeze interogarea.

înlocuiți șirul în java

În loc să vă arate detaliile utilizatorului, aplicația va returna o eroare SQL (ceva de genul „Aveți o eroare în sintaxa dvs. SQL…”)

Aceasta se numește Injecție SQL bazată pe erori deoarece:

  • Atacatorul trimite o intrare nevalidă (')
  • Baza de date afișează o eroare
  • Această eroare furnizează informații utile despre baza de date (cum ar fi tipul de structură a numărului de coloane DB etc.)

2. Injecție SQL bazată pe uniuni

Injecția SQL bazată pe uniuni este o tehnică în care atacatorii folosescUNIONoperator pentru a combina rezultatele a două sau mai multeSELECTdeclarații într-un singur set de rezultate. Acest lucru le poate permite să extragă informații din alte tabele din baza de date. TheUNIONoperatorul poate fi utilizat numai dacă:

  • Ambele interogări au același număr de coloane
  • Coloanele au tipuri de date similare
  • Coloanele sunt în aceeași ordine

Operator UNION : TheUNIONoperatorul este folosit pentru a combina setul de rezultate din două sau mai multeSELECTdeclarații.

  • FiecareSELECTdeclarație în cadrulUNIONtrebuie să aibă același număr de coloane
  • Coloanele trebuie să aibă tipuri de date similare
  • Coloanele trebuie să fie în aceeași ordine
SELECT column_name(s) FROM table1UNIONSELECT column_name(s) FROM table2

Exemplu:

Pasul 1: În primul rând, trebuie să găsim numărul de coloane din tabelul existent pe site-ul web pentru a injecta injectarea SQL bazată pe UNION:

Pagina SQL Injection are o casetă de introducere simplă în care puteți introduce un ID de utilizator. Interogarea backend este probabil ceva de genul

 SELECT * FROM users WHERE id = 'user_input'

Acum încercați să întrerupeți interogarea. Introduceți un singur citat'în caseta de introducere și trimiteți.

Dacă aplicația este vulnerabilă, veți primi un mesaj de eroare detaliat. Ar putea arăta ceva de genul:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1

Pasul 2: UtilizațiUNIONCuvânt cheie pentru a descoperi numărul de coloane

Pentru a utilizaUNIONcuvânt cheie (un următor pas comun) trebuie să cunoașteți numărul de coloane din interogarea inițială. Puteți afla acest lucru folosindORDER BYclauză

„abc” este în cifre”
  • Încercați să sortați rezultatele după coloană
1: 1 ORDER BY 1. 
  • Trimiteți. Ar trebui să funcționeze.
fişier' loading='lazy' title=

Sursa de injectare SQL

PHP
 if( isset( $_REQUEST[ 'Submit' ] ) ) { // Get input $id = $_REQUEST[ 'id' ]; switch ($_DVWA['SQLI_DB']) { case MYSQL: // Check database $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; $result = mysqli_query($GLOBALS['___mysqli_ston'] $query ) or die( '
' . ((is_object($GLOBALS['___mysqli_ston'])) ? mysqli_error($GLOBALS['___mysqli_ston']) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
'
); // Get results while( $row = mysqli_fetch_assoc( $result ) ) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo '
ID: {$id}  
First name:
{$first}
Surname:
{$last}
'
; } mysqli_close($GLOBALS['___mysqli_ston']); break; case SQLITE: global $sqlite_db_connection; #$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']); #$sqlite_db_connection->enableExceptions(true); $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; #print $query; try { $results = $sqlite_db_connection->query($query); } catch (Exception $e) { echo 'Caught exception: ' . $e->getMessage(); exit(); } if ($results) { while ($row = $results->fetchArray()) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo '
ID: {$id}  
First name:
{$first}
Surname:
{$last}
'
; } } else { echo 'Error in fetch '.$sqlite_db->lastErrorMsg(); } break; } } ?>
  • Creșteți numărul:
 1 ORDER BY 2. 

Trimiteți. Ar trebui să funcționeze.

fişier' loading='lazy' title=
  • Continuați să creșteți până când primiți o eroare. De exemplu1 ORDER BY 4s-ar putea sa iti ofere:Unknown column '4' in 'order clause'
  • Aceasta înseamnă că interogarea are 3 coloane.

3. Blind-Based SQL Injection

Blind SQL Injection apare atunci când atacatorii nu pot vedea rezultatele interogării direct pe pagina web. În schimb, ei deduc informații din modificări subtile în comportamentul aplicației sau timpul de răspuns. Deși mai lent și mai obositor decât SQLi clasic, poate fi la fel de eficient.

În loc să recupereze datele, atacatorul deduce informații observând comportamentul paginii web. Acest lucru se face de obicei într-unul din două moduri:

  1. SQLi orb bazat pe boolean: Atacatorul injectează o interogare SQL care returnează a adevărat sau fals rezultat. Răspunsul aplicației web se modifică în funcție de faptul că interogarea este adevărată sau falsă. De exemplu, pagina poate afișa un mesaj diferit sau poate reda un aspect diferit.
  2. SQLi orb bazat pe timp: Atacatorul injectează o interogare SQL care face ca baza de date să efectueze o acțiune consumatoare de timp (cum ar fi oSLEEP()funcția) dacă este îndeplinită o condiție. Atacatorul observă timpul necesar pentru încărcarea paginii pentru a determina dacă condiția injectată a fost adevărată sau falsă.

Exemplu:

Imaginați-vă o pagină de conectare în care introduceți un nume de utilizator și o parolă. Aplicația construiește o interogare SQL astfel:

SELECT * FROM users WHERE username = 'user_input' AND password = 'password_input'

O injecție oarbă SQL ar implica manipularea fișieruluiuser_inputcâmp pentru a adresa o întrebare bazei de date.

În loc să obțină un răspuns direct, atacatorul ar putea încerca ceva de genul acesta:

user_input = 'admin' AND 1=1; --

Dacă pagina se încarcă normal, atacatorul știe asta1=1este o adevărat declaraţie.

user_input = 'admin' AND 1=2; --

Dacă pagina arată o eroare sau se comportă diferit, atacatorul știe asta1=2este o fals declaraţie.

fişier' loading='lazy' title=

Folosind o serie de aceste întrebări adevărat/fals, un atacator poate ghici și extrage în mod sistematic informații câte un caracter. Procesul poate fi automatizat pentru a ghici totul, de la numele tabelelor la parolele utilizatorilor.

Impactul atacurilor prin injecție SQL

  • Acces neautorizat la date sensibile : Atacatorii pot prelua informații financiare personale sau confidențiale stocate în baza de date.
  • Probleme de integritate a datelor : Atacatorii pot modifica ștergerea sau coruperea datelor critice care afectează funcționalitatea aplicației.
  • Escaladarea privilegiilor : Atacatorii pot ocoli mecanismele de autentificare și pot obține privilegii administrative.
  • Timp de nefuncționare a serviciului : injecția SQL poate supraîncărca serverul, cauzând degradarea performanței sau blocarea sistemului.
  • Daune reputației : Un atac de succes poate afecta grav reputația unei organizații, ducând la pierderea încrederii clienților.

Prevenirea atacurilor prin injecție SQL

Există câteva bune practici pentru a preveni atacurile prin injecție SQL:

1. Utilizați instrucțiuni pregătite și interogări parametrizate

Declarațiile pregătite și interogările parametrizate asigură că intrările utilizatorului sunt tratate ca date și nu ca parte a interogării SQL. Această abordare elimină riscul injectării SQL.

Exemplu în PHP (folosind MySQLi):

$stmt = $conn->prepare('SELECT * FROM users WHERE username = ? AND password = ?'); $stmt->bind_param('ss' $username $password); $stmt->execute();

2. Folosiți proceduri stocate

Procedurile stocate sunt interogări SQL predefinite stocate în baza de date. Aceste proceduri pot ajuta la prevenirea injectării SQL, deoarece nu construiesc dinamic interogări SQL.

Exemplu:

CREATE PROCEDURE GetUserByUsername (IN username VARCHAR(50)) BEGIN SELECT * FROM users WHERE username = username; END;

3. Validarea intrărilor pe lista albă

Asigurați-vă că intrările utilizatorului sunt validate înainte de a fi utilizate în interogările SQL. Permiteți numai anumite caractere și modele, cum ar fi introducerea alfanumerice, pentru câmpuri precum numele de utilizator sau adresele de e-mail.

fizzbuzz java

4. Utilizați cadre ORM

Cadre de cartografiere obiect-relațională (ORM) cum ar fi Hibernează sau Entity Framework poate ajuta la prevenirea injectării SQL prin gestionarea automată a generării de interogări, prevenind construcția dinamică a interogărilor.

5. Restricționați privilegiile bazei de date

Acordați permisiunile minime necesare pentru baze de date utilizatorilor. Asigurați-vă că aplicațiile pot efectua numai acțiunile necesare (de exemplu, SELECT INSERT) și restricționează permisiunile precum DROP TABLE sau ALTER.

6. Tratarea erorilor

Configurați baza de date și aplicația pentru a nu afișa utilizatorului mesaje de eroare detaliate. În schimb, înregistrați erorile în interior și afișați mesaje de eroare generice pentru utilizatorii finali.