arrow_backÎnapoi la field notes
WEB SECURITY Publicat 8 Aug 2026

Ce este SQL Injection și cum o preîntâmpini?

O analiză practică a atacurilor SQL injection, exemple reale și corecțiile concrete care le opresc într-adevăr în cod de producție.

SQL injection există din finele anilor 1990 și rămâne una dintre cele mai comune modalități în care aplicațiile web sunt compromise. Greșeala este simplă: un atacator trimite intrări care se interpretează ca cod SQL în loc de date obișnuite, iar baza de date execută ceva ce nu ar trebui să execute.

Cum funcționează atacul efectiv

Imaginează un formular de autentificare care construiește o interogare așa în PHP:

$query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";

Dacă aplicația nu curață intrările, un atacator introduce admin' -- în câmpul de utilizator. Interogarea devine:

SELECT * FROM users WHERE username = 'admin' --' AND password = ''

Secvența -- comentează restul liniei, deci verificarea parolei nu se întâmplă niciodată. Acesta este un bypass de autentificare clasic. Atacatorii folosesc și UNION SELECT pentru a extrage date din alte tabele, sau stivuiesc interogări cu punct și virgulă pentru a executa ceva distructiv cum ar fi DROP TABLE users; dacă driverul permite mai multe instrucțiuni.

Există și SQL injection oarbă, unde aplicația nu afișează direct rezultatele interogării. Atacatorii deduc informații prin temporire (SLEEP(5) în MySQL) sau răspunsuri booleene (pagina se comportă diferit pentru o condiție adevărată versus falsă). Unelte cum ar fi sqlmap automatizează acest fel de extragere odată ce se găsește un parametru vulnerabil.

De ce concatenarea șirurilor este problema rădăcină

Fiecare variant al acestui atac se întoarce la o chestie: amestecarea codului și datelor în același șir. Baza de date nu poate face diferența între o valoare legitimă și sintaxa injectată deoarece ajung pe același canal. Evitarea ghilimelelor ajută în unele cazuri, dar este fragil — codificări diferite, injecție de ordinul doi (date stocate o dată, apoi reutilizate nesigur mai târziu) și idiosincraziile driverului, toate acestea creează căi de bypass. Evitarea este o patch-uri, nu o reparație.

Interogările parametrizate sunt reparația reală

Reparația este separarea codului SQL de datele utilizatorului la nivelul driverului, folosind interogări parametrizate (numite și prepared statements). Baza de date primește mai întâi structura interogării, apoi leagă valorile după, deci intrarea utilizatorului nu poate niciodată schimba semnificația interogării.

În Python cu psycopg2:

cur.execute("SELECT * FROM users WHERE username = %s AND password = %s", (username, password))

În Node.js cu mysql2:

connection.execute('SELECT * FROM users WHERE username = ? AND password = ?', [username, password]);

În Java cu JDBC:

PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users WHERE username = ? AND password = ?");
stmt.setString(1, username);
stmt.setString(2, password);

Observă modelul: substituenți (%s, ?) iau locul datelor, și valorile reale se transmit separat. Fără concatenare de șiruri, fără evitare manuală. Asta funcționează pentru marea majoritate a interogărilor pe care le vei scrie într-o aplicație normală.

Ce zici de tabelele sau coloanele dinamice?

Parametrizarea gestionează valorile, dar nu și identificatorii — nu poți lega un nume de tabel ca parametru. Dacă aplicația trebuie să selecteze un tabel dinamic (rar, și des o miros de design), pune pe lista albă valorile permise față de o listă hardcod în loc să te încrezui direct în intrarea utilizatorului:

allowed_tables = {'orders', 'invoices', 'customers'}
if table_name not in allowed_tables:
    raise ValueError("Invalid table")

Nicicând nu construi nume de identificatori prin formatare de șiruri din intrarea utilizatorului, chiar și cu evitare.

Apărări în straturi dincolo de interogare

Interogările parametrizate sunt controlul primar, dar câteva alte lucruri contează:

  • Privilegiu minim pe contul bazei de date. Utilizatorul DB al aplicației nu ar trebui să aibă DROP, ALTER sau acces la scheme nerelaționate. Dacă o injecție alunecă totuși, privilegiile limitate limitează daunele.
  • ORM-urile ajută în mod implicit. ORM-ul Django, SQLAlchemy și Hibernate parametrizează toate interogările automat când folosești metodele lor standard de construire a interogărilor. Riscul reapare când dezvoltatorii cad în SQL brut sau folosesc apeluri .extra()/text() cu interpolare de șiruri — deci auditează acele locuri în mod specific.
  • Validarea intrării este un strat secundar, nu o înlocuitor. Verificarea că un câmp de email arată ca un email este o bună practică, dar nu oprește injecția singură — atacatorii găsesc payloade creative care trec încă prin validarea loosă.
  • Un WAF poate prinde modele de atac cunoscute, dar este un strat de detecție, nu o reparație pentru codul subiacent.

Testează codul tău pentru această greșeală

Treci-ți interogările printr-o unealtă de analiză statică (Bandit pentru Python, Semgrep cu ruluri SQL injection) ca parte a CI. Pentru testare manuală, încearcă să injectezi o ghilimă singură (') în fiecare câmp de intrare și urmărește mesajele de eroare SQL care scapă în răspuns — asta este adesea semnul întâi că o interogare nu este parametrizată.

Dacă vrei să mergi mai adânc pe asta, Korra Studio's Web Security track acoperă injecția alături de XSS și auth bypass, iar segmentele Databases te duc prin modele de design de interogări care evit complet această clasă de greșeală.

Scris cu asistență AI, revizuit și publicat de Michal Pilch (CISSP), Korra Studio.

Gata să mergi mai departe?

Aceasta este o notă din baza de cunoștințe Korra Studio — platforma asociază fiecare subiect cu mentorat 1-la-1.

Început gratuitarrow_forward