Situația actuală: PHP2Shell. Două vulnerabilități critice PHP (CVSS 9.2) permit cod malițios fără autentificare. Patchuri din 21.10.2026.Ce este de făcut acum →

Cum preveniți SQL injection în PHP

Cum exclud dezvoltatorii în mod fiabil SQL injection în aplicațiile PHP, cu prepared statements, liste albe și drepturi minime în baza de date.

Stadiu 5 min de cititGhiduri

Pe scurt: Preveniți SQL injection în PHP în mod fiabil dacă nu încorporați niciodată valori în textele SQL, ci le transmiteți întotdeauna prin prepared statements cu substituenți. Pentru numele de coloane și de tabele, care nu pot fi transmise ca substituenți, se aplică o listă albă fixă. În plus, un utilizator de bază de date cu drepturi minime limitează paguba dacă totuși rămâne o vulnerabilitate.

De ce SQL injection nu trebuie pierdut din vedere după PHP2Shell

În octombrie 2026, multe lucruri se învârt în jurul PHP2Shell, două vulnerabilități critice în interpretorul PHP, corectate din 21.10.2026 în PHP 8.5.12, 8.4.27, 8.3.36 și 8.2.35. Multe echipe au actualizat în aceste zile servere și au repornit procese. Este corect și urgent.

O versiune PHP actuală nu spune însă nimic despre codul propriu. SQL injection se numără de ani de zile printre cele mai frecvente slăbiciuni din aplicațiile web și este inclus în OWASP Top 10 la categoria Injection. Cine oricum planifică verificări de securitate ar trebui să includă imediat și accesările bazei de date ale propriei aplicații.

Vestea bună: SQL injection este una dintre puținele slăbiciuni care pot fi excluse aproape complet cu o regulă simplă, aplicată consecvent.

Cum apare SQL injection în PHP?

SQL injection apare când o aplicație tratează datele introduse de utilizator ca parte a unei comenzi SQL, în loc să le trateze ca date pure. Tipic este asamblarea unei interogări din bucăți de text și variabile. Dacă un vizitator poate determina conținutul unei asemenea variabile, el poate, în anumite condiții, schimba sensul comenzii.

Consecințele merg de la citirea datelor altor clienți, prin modificarea prețurilor sau a drepturilor, până la ștergerea unor tabele întregi. În funcție de baza de date și de drepturi, o vulnerabilitate poate permite și accesuri dincolo de baza de date. Dacă sunt afectate date cu caracter personal, poate apărea o obligație de notificare conform RGPD.

Datele de intrare nu sunt aici doar câmpurile de formular. Și parametrii URL, cookieurile, antetele HTTP, fișierele încărcate, răspunsurile interfețelor străine și datele deja stocate în propria bază de date sunt considerate nesigure.

Prepared statements cu PDO și mysqli

Prepared statements trimit comanda SQL și valorile separat către baza de date. Valorile nu sunt niciodată interpretate ca parte a comenzii. Cu PDO, o interogare sigură arată astfel:

<?php
$pdo = new PDO($dsn, $benutzer, $passwort, [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_EMULATE_PREPARES   => false,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);

$stmt = $pdo->prepare('SELECT id, name, email FROM kunden WHERE id = :id AND status = :status');
$stmt->execute([
    'id'     => (int) $_GET['id'],
    'status' => 'aktiv',
]);
$kunde = $stmt->fetch();

Opțiunea PDO::ATTR_EMULATE_PREPARES => false face ca baza de date să folosească prepared statements reale, în măsura în care driverul o permite. Cu mysqli se aplică același principiu:

<?php
$stmt = $mysqli->prepare('SELECT id, name FROM produkte WHERE kategorie = ? AND preis <= ?');
$stmt->bind_param('sd', $kategorie, $maxPreis);
$stmt->execute();
$ergebnis = $stmt->get_result();

Și listele pentru IN (...) pot fi redate în siguranță, creând pentru fiecare valoare un substituent propriu și transmițând valorile separat.

<?php
$ids = array_map('intval', $ausgewaehlteIds);
$platzhalter = implode(',', array_fill(0, count($ids), '?'));
$stmt = $pdo->prepare("SELECT id, name FROM produkte WHERE id IN ($platzhalter)");
$stmt->execute($ids);

Cazuri speciale: nume de coloane, sortare și SQL brut

Substituenții funcționează doar pentru valori, nu pentru nume de tabele, nume de coloane sau direcții de sortare. Tocmai aici apar în practică multe vulnerabilități, de exemplu la tabele sortabile sau la filtre. Soluția este o listă fixă de valori permise:

<?php
$erlaubteSpalten = ['name' => 'name', 'preis' => 'preis', 'datum' => 'erstellt_am'];
$spalte   = $erlaubteSpalten[$_GET['sort'] ?? ''] ?? 'name';
$richtung = (($_GET['dir'] ?? '') === 'desc') ? 'DESC' : 'ASC';

$stmt = $pdo->query("SELECT id, name, preis FROM produkte ORDER BY $spalte $richtung");

Frameworkurile și CMS-urile vin cu instrumente proprii. În WordPress, $wpdb->prepare() preia această sarcină, în Laravel și Symfony query builder-ele și ORM-urile. De îndată ce folosiți acolo SQL brut, de exemplu prin funcții cu „raw” în nume, se aplică din nou regulile acestei secțiuni. Indicații despre Laravel găsiți la Cum securizați aplicațiile Laravel.

Sfat

Căutați țintit în cod texte SQL în care sunt introduse variabile. Un început simplu este o căutare după query( și ->raw în combinație cu $_GET, $_POST sau $_REQUEST.

Depistarea SQL injection în codul existent

La software nou, regula poate fi respectată din start. Mai dificil este la aplicațiile crescute de-a lungul anilor. Acolo merită o căutare sistematică a locurilor în care textele SQL sunt asamblate cu variabile:

# Comenzi SQL în care sunt introduse variabile
grep -rnE "(SELECT|INSERT|UPDATE|DELETE)[^;]*\\\$[a-zA-Z_]" src/ --include="*.php" | head -50
# Folosirea directă a datelor cererii în funcții de interogare
grep -rnE "(query|exec|raw)\s*\(.*\\\$_(GET|POST|REQUEST|COOKIE)" src/ --include="*.php"

Nu orice rezultat este o vulnerabilitate, de exemplu dacă variabila conține doar un nume de tabel fix. Fiecare loc găsit ar trebui însă verificat conștient o dată și, la nevoie, trecut la prepared statements. Instrumentele de analiză statică a codului ajută să recunoașteți durabil asemenea tipare în pipeline-ul de build, astfel încât erorile noi să nu ajungă deloc în producție.

Limitarea pagubei: drepturi, mesaje de eroare, verificare

Codul sigur este prima linie de apărare. Alte niveluri limitează paguba dacă totuși se scapă o vulnerabilitate:

  • Drepturi minime: Utilizatorul de bază de date al site-ului are nevoie, de regulă, doar de SELECT, INSERT, UPDATE și DELETE pe propria bază de date, fără drepturi de creare a utilizatorilor sau de acces la alte baze de date.
  • Fără mesaje de eroare către exterior: display_errors = Off în php.ini. Erorile bazei de date aparțin logului, nu browserului.
  • Separare pe aplicație: Fiecare site primește un utilizator de bază de date propriu.
  • Dependențe la zi: Vulnerabilitățile se ascund și în biblioteci, așa cum arată ghidul composer audit.
  • Verificare externă: Code review-ul și analiza automatizată găsesc multe locuri, un test de penetrare arată ce este efectiv accesibil din exterior.
-- Exemplu: utilizator de bază de date doar cu drepturile necesare
CREATE USER 'shop_app'@'localhost' IDENTIFIED BY '<starkes Passwort>';
GRANT SELECT, INSERT, UPDATE, DELETE ON shop.* TO 'shop_app'@'localhost';

O slăbiciune înrudită privește afișarea datelor în browser. Cum o securizați explică ghidul Cum preveniți Cross-Site Scripting în PHP.

Cum ajută PHP SOS concret?

  • Verificăm sistematic accesările bazei de date ale aplicației dumneavoastră pentru interogări nesigure.
  • Prioritizăm constatările după accesibilitate și datele afectate și arătăm corecturi concrete.
  • Aducem drepturile bazei de date și tratarea erorilor la un nivel sigur.
  • După corectare testăm din nou și documentăm rezultatul.

O verificare independentă o descrie serviciul Audit de securitate și test de penetrare.

Întrebări frecvente

Este suficient să tratez datele de intrare cu addslashes sau real_escape_string?

Nu, este predispus la erori. Escaparea depinde de setul de caractere și de context și este uitată ușor într-un loc. Prepared statements separă fundamental comanda de date și sunt de aceea calea recomandată.

Protejează un ORM automat împotriva SQL injection?

În mare măsură, atâta timp cât folosiți funcțiile de interogare ale ORM. De îndată ce scrieți SQL brut sau introduceți valori în sortări și nume de coloane, se aplică aceleași reguli ca fără ORM.

Ajută un Web Application Firewall împotriva SQL injection?

Un WAF poate opri tipare cunoscute și poate câștiga timp. Nu înlocuiește însă codul sigur, deoarece regulile bazate pe datele cererii pot fi ocolite și uneori lovesc date de intrare legitime.

Închide actualizarea PHP împotriva PHP2Shell și vulnerabilitățile SQL injection?

Nu. PHP2Shell afectează interpretorul PHP. SQL injection este o eroare în codul aplicației și rămâne, indiferent ce versiune PHP rulează.

Surse

Contact imediat

Fiecare oră contează. Scrieți-ne acum.

Descrieți pe scurt sistemul, versiunea PHP și ce ați observat. Ne vom face auziți, clarificăm situația și lucrăm la distanță până când incidentul este încheiat și documentat.

Ajutor imediat