# SQL-injection megelőzése PHP-ban

> SQL-injection megelőzése PHP-ban: Prepared Statements PDO-val és mysqli-vel, engedélylisták oszlopokhoz, szűk adatbázisjogok. Példákkal, ellenőrzőlistával.

Forrás: https://phpsos.de/hu/ratgeber/sql-injection-php/  
Állapot: 2026. 10. 25.  
Szolgáltató: PHP SOS, PHP-vészhelyzeti segítség és szerverbiztonság. Azonnali segítség WhatsAppon: https://wa.me/491736494914?text=%C3%9Cdv%C3%B6zl%C3%B6m%2C%20PHP%20SOS%21%20Seg%C3%ADts%C3%A9gre%20van%20sz%C3%BCks%C3%A9g%C3%BCnk%20a%20PHP-szerver%C3%BCnkkel.%20C%C3%A9g%3A%20%E2%80%A6%20Weboldal%3A%20%E2%80%A6

**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
<?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
<?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
<?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
<?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](https://phpsos.de/hu/plattformen/laravel/) 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:

```bash
# 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](https://phpsos.de/hu/ratgeber/composer-abhaengigkeiten-pruefen/) ú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.

```sql
-- 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](https://phpsos.de/hu/ratgeber/xss-php/) ú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](https://phpsos.de/hu/leistungen/sicherheitsaudit-penetrationstest/) 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

- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/)
- [php.net: biztonsági közlemények](https://www.php.net/)
