Aktuális helyzet: PHP2Shell. Két kritikus PHP-rés (CVSS 9,2) lehetővé teszi kártékony kód futtatását bejelentkezés nélkül. Javítások 2026. 10. 21. óta.Mi a teendő most →

SQL-injection megelőzése PHP-ban

Hogyan zárják ki a fejlesztők megbízhatóan az SQL-injectiont a PHP-alkalmazásokban Prepared Statementekkel, engedélylistákkal és minimális adatbázisjogokkal.

Állapot 5 perc olvasási időÚtmutatók

Röviden: Az SQL-injectiont PHP-ban megbízhatóan úgy előzi meg, hogy az értékeket soha nem építi be az SQL-szövegbe, hanem mindig Prepared Statementeken keresztül, helyőrzőkkel adja át. Az oszlop- és táblanevekre, amelyeket nem lehet helyőrzőként átadni, rögzített engedélylista érvényes. Emellett egy minimális jogokkal rendelkező adatbázis-felhasználó korlátozza a kárt arra az esetre, ha mégis marad rés.

Miért nem szabad szem elől téveszteni az SQL-injectiont a PHP2Shell után

2026 októberében sok minden a PHP2Shell körül forog, a PHP-értelmezőben lévő két kritikus rés körül, amelyeket 2026. 10. 21. óta a PHP 8.5.12, 8.4.27, 8.3.36 és 8.2.35 verzió javít. Sok csapat ezekben a napokban frissítette a szervereket és indította újra a folyamatokat. Ez helyes és sürgős.

Egy aktuális PHP-állapot azonban semmit sem mond a saját kódról. Az SQL-injection évek óta a webalkalmazások leggyakoribb sebezhetőségei közé tartozik, és az OWASP Top 10 az Injection kategória alatt tartja számon. Aki úgyis biztonsági vizsgálatokat tervez, az alkalmazása adatbázis-hozzáféréseit is nézze át egyúttal.

A jó hír: az SQL-injection egyike azoknak a ritka sebezhetőségeknek, amelyeket egy egyszerű, következetesen alkalmazott szabállyal szinte teljesen ki lehet zárni.

Hogyan keletkezik az SQL-injection PHP-ban?

Az SQL-injection akkor keletkezik, ha egy alkalmazás a felhasználói bemeneteket egy SQL-parancs részeként kezeli, nem pusztán adatként. Tipikus egy lekérdezés összeállítása szövegrészekből és változókból. Ha egy látogató meghatározhatja egy ilyen változó tartalmát, bizonyos körülmények között megváltoztathatja a parancs jelentését.

A következmények az idegen ügyféladatok kiolvasásától az árak vagy jogok módosításán át egész táblák törléséig terjednek. Az adatbázistól és a jogoktól függően egy rés az adatbázison túli hozzáféréseket is lehetővé tehet. Ha személyes adatok érintettek, a GDPR szerinti bejelentési kötelezettség keletkezhet.

A bemenetek nem csak az űrlapmezők. Az URL-paraméterek, a cookie-k, a HTTP-fejlécek, a feltöltött fájlok, az idegen interfészek válaszai és a saját adatbázisból már tárolt adatok is megbízhatatlannak számítanak.

Prepared Statementek PDO-val és mysqli-vel

A Prepared Statementek az SQL-parancsot és az értékeket külön küldik az adatbázisnak. Az értékeket soha nem értelmezik a parancs részeként. PDO-val egy biztonságos lekérdezés így néz ki:

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

A PDO::ATTR_EMULATE_PREPARES => false opció gondoskodik arról, hogy az adatbázis valódi Prepared Statementeket használjon, amennyiben a meghajtó támogatja. A mysqli-vel ugyanez az elv érvényes:

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

Az IN (...) listák is biztonságosan megoldhatók, ha minden értékhez külön helyőrzőt hoz létre, és az értékeket külön adja át.

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

Különleges esetek: oszlopnevek, rendezés és nyers SQL

A helyőrzők csak értékekre működnek, táblanevekre, oszlopnevekre vagy rendezési irányokra nem. A gyakorlatban éppen itt keletkezik sok rés, például rendezhető táblázatoknál vagy szűrőknél. A megoldás az engedélyezett értékek rögzített listája:

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

A keretrendszerek és a CMS-ek saját eszközöket hoznak magukkal. A WordPressben a $wpdb->prepare() veszi át ezt a feladatot, a Laravelben és a Symfonyban a Query Builderek és az ORM-ek. Amint ott nyers SQL-t használ, például a nevükben „raw“ szót tartalmazó függvényeken keresztül, ismét az ebben a szakaszban leírt szabályok érvényesek. A Laravelről a Laravel-alkalmazások védelme oldalon talál tudnivalókat.

Tipp

Célzottan keressen a kódban olyan SQL-szövegeket, amelyekbe változókat illesztenek. Egyszerű kezdet a query( és a ->raw keresése a $_GET, $_POST vagy $_REQUEST kombinációjában.

SQL-injection felderítése a meglévő kódban

Új szoftvernél a szabály az elejétől fogva betartható. Nehezebb ez az évek alatt kialakult alkalmazásoknál. Ott megéri módszeresen keresni azokat a helyeket, ahol az SQL-szövegeket változókkal állítják össze:

# SQL-parancsok, amelyekbe változókat illesztenek
grep -rnE "(SELECT|INSERT|UPDATE|DELETE)[^;]*\\\$[a-zA-Z_]" src/ --include="*.php" | head -50
# Kérésadatok közvetlen használata lekérdező függvényekben
grep -rnE "(query|exec|raw)\s*\(.*\\\$_(GET|POST|REQUEST|COOKIE)" src/ --include="*.php"

Nem minden találat rés, például ha a változó csak egy rögzített táblanevet tartalmaz. Minden lelőhelyet azonban egyszer tudatosan ellenőrizni kell, és szükség esetén Prepared Statementekre kell átállítani. A statikus kódelemző eszközök segítenek az ilyen minták tartós felismerésében a build-pipeline-ban, hogy az új hibák ne kerüljenek élesbe.

A kár korlátozása: jogok, hibaüzenetek, ellenőrzés

A biztonságos kód az első védvonal. További szintek korlátozzák a kárt arra az esetre, ha mégis átnéznek egy rést:

  • Minimális jogok: A weboldal adatbázis-felhasználójának többnyire csak SELECT, INSERT, UPDATE és DELETE jogra van szüksége a saját adatbázisán, nem kell joga felhasználók létrehozásához vagy más adatbázisok eléréséhez.
  • Ne kerüljenek hibaüzenetek kifelé: display_errors = Off a php.ini-ben. Az adatbázishibák a naplóba valók, nem a böngészőbe.
  • Alkalmazásonkénti elválasztás: Minden weboldal saját adatbázis-felhasználót kap.
  • A függőségek legyenek naprakészek: Rések a könyvtárakban is lehetnek, ahogy a composer audit útmutató mutatja.
  • Ellenőriztesse: A kódellenőrzés és az automatizált elemzés sok helyet megtalál, a penetrációs teszt megmutatja, mi érhető el ténylegesen kívülről.
-- Példa: adatbázis-felhasználó csak a szükséges jogokkal
CREATE USER 'shop_app'@'localhost' IDENTIFIED BY '<starkes Passwort>';
GRANT SELECT, INSERT, UPDATE, DELETE ON shop.* TO 'shop_app'@'localhost';

Egy rokon sebezhetőség az adatok böngészőben való megjelenítését érinti. Hogyan védheti ezt, azt a A Cross-Site Scripting megelőzése PHP-ban útmutató magyarázza.

Hogyan segít konkrétan a PHP SOS?

  • Módszeresen ellenőrizzük az alkalmazása adatbázis-hozzáféréseit nem biztonságos lekérdezések szempontjából.
  • A leleteket az elérhetőség és az érintett adatok szerint rangsoroljuk, és konkrét javításokat mutatunk.
  • Az adatbázisjogokat és a hibakezelést biztonságos szintre állítjuk.
  • A javítás után újra tesztelünk, és dokumentáljuk az eredményt.

Egy független ellenőrzést a Biztonsági audit és penetrációs teszt szolgáltatás ír le.

Gyakori kérdések

Elég a bemeneteket az addslashes-sel vagy a real_escape_string-gel kezelni?

Nem, ez hibára hajlamos. Az escape-elés a karakterkészlettől és a környezettől függ, és könnyen elfelejtik egy helyen. A Prepared Statementek elvileg elválasztják a parancsot és az adatot, ezért ez az ajánlott út.

Automatikusan véd egy ORM az SQL-injection ellen?

Nagyrészt, amíg az ORM lekérdező függvényeit használja. Amint nyers SQL-t ír, vagy értékeket illeszt rendezésekbe és oszlopnevekbe, ugyanazok a szabályok érvényesek, mint ORM nélkül.

Segít egy Web Application Firewall az SQL-injection ellen?

Egy WAF elfoghatja az ismert mintákat, és időt nyerhet. Biztonságos kódot azonban nem pótol, mert a kérésadatok alapján felállított szabályok megkerülhetők, és időnként jogos bemeneteket is eltalálnak.

A PHP2Shell elleni PHP-frissítés az SQL-injection réseket is lezárja?

Nem. A PHP2Shell a PHP-értelmezőt érinti. Az SQL-injection az alkalmazáskód hibája, és fennmarad, bármelyik PHP-verzió fut.

Források

Azonnali kapcsolat

Minden óra számít. Írjon nekünk most.

Ismertesse röviden a rendszert, a PHP-verziót és a megfigyelését. Jelentkezünk, tisztázzuk a helyzetet, és távolról dolgozunk, amíg az incidens le nem zárul és dokumentálva nem lesz.

Azonnali segítség