# Nem biztonságos deszerializáció PHP-ban: unserialize és biztonság

> A PHP unserialize biztonságos használata: miért veszélyesek a felhasználói bevitelből jövő objektumok, hogyan véd a JSON, az allowed_classes és az aláírás.

Forrás: https://phpsos.de/hu/ratgeber/deserialisierung-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:** A PHP unserialize biztonságánál egy egyszerű szabály érvényes: a kívülről érkező adatokat soha ne dolgozza fel az `unserialize()`-zal. Használjon helyette JSON-t. Ahol az `unserialize()` régi kódból megmaradni kényszerül, korlátozza az `allowed_classes => false` beállítással, és az adatok eredetiségét ellenőrizze aláírással.

## Mi romolhat el az unserialize()-nál

A PHP tömböket és objektumokat a `serialize()`-zal szöveggé alakíthat, és az `unserialize()`-zal visszaállíthat. Ez kényelmes az adatok cookie-kban, gyorsítótárakban vagy adatbázismezőkben való tárolására. A probléma: az `unserialize()` közben tetszőleges osztályok objektumait is létrehozza, amelyek az alkalmazásban betölthetők.

Egy ilyen objektum létrehozásakor és legkésőbb megsemmisítésekor a PHP automatikusan meghív bizonyos metódusokat, például a `__wakeup()`-ot, az `__unserialize()`-t vagy a `__destruct()`-ot. Ha a projektben vagy a könyvtárakban lévő osztályok ilyen metódusokat tartalmaznak fájl-, adatbázis- vagy rendszerműveletekkel, a támadó manipulált adatokkal visszaélhet velük. A szakemberek PHP Object Injectionről beszélnek. A meglévő osztályoktól függően a hatás egyes fájlok törlésétől a kártékony kód futtatásáig terjed.

Nem műszaki embereknek összefoglalva: egyetlen meggondolatlan hívás a rossz helyen messzire engedheti a támadót az alkalmazásban. Ez a sebezhetőség ezért évek óta az OWASP Top 10 témái közé tartozik.

## A biztonságos alternatíva: JSON az unserialize helyett

Szinte minden esetben, amikor az adatok kívülről érkeznek vagy elhagyják a szervert, a JSON a helyes választás. A `json_decode()` csak tömböket, számokat, karakterláncokat és logikai értékeket hoz létre, saját osztályok objektumait nem.

```php
<?php
declare(strict_types=1);

function leseEinstellungen(string $eingabe): array
{
    try {
        $daten = json_decode($eingabe, true, 16, JSON_THROW_ON_ERROR);
    } catch (JsonException $e) {
        throw new InvalidArgumentException('Ungültige Daten.');
    }

    if (!is_array($daten)) {
        throw new InvalidArgumentException('Erwartet wurde ein Objekt.');
    }

    // Csak az ismert mezőket vegye át, a várt típusokkal
    return [
        'sprache' => in_array($daten['sprache'] ?? '', ['de', 'en'], true) ? $daten['sprache'] : 'de',
        'seiten'  => max(1, min(100, (int) ($daten['seiten'] ?? 20))),
    ];
}
```

A második rész a fontos: a JSON-adatok is bemenetek. Csak a várt mezőket vegye át, és ellenőrizze a típusokat és az értéktartományokat, mielőtt dolgozna velük.

## Ha az unserialize elkerülhetetlen: allowed_classes és aláírás

A régebbi alkalmazásokban a szerializált adatok gyakran olyan adatbázisokban vagy gyorsítótárakban vannak, amelyeket nem lehet azonnal átállítani. Ekkor két lépésben korlátozza a kockázatot. Először az `allowed_classes`-szal megakadályozza, hogy objektumok jöjjenek létre. Másodszor egy HMAC-aláírással biztosítja, hogy az adatok ténylegesen az Ön alkalmazásától származnak, és útközben nem módosították őket.

```php
<?php
declare(strict_types=1);

const SCHLUESSEL = 'aus-sicherer-konfiguration-laden'; // soha ne a kódtárolóban

function verpacken(array $daten): string
{
    $roh = serialize($daten);
    return hash_hmac('sha256', $roh, SCHLUESSEL) . '.' . base64_encode($roh);
}

function auspacken(string $paket): array
{
    [$signatur, $b64] = array_pad(explode('.', $paket, 2), 2, '');
    $roh = base64_decode($b64, true);

    if ($roh === false || !hash_equals(hash_hmac('sha256', $roh, SCHLUESSEL), $signatur)) {
        throw new RuntimeException('Signatur ungültig.');
    }

    $daten = unserialize($roh, ['allowed_classes' => false, 'max_depth' => 16]);
    if (!is_array($daten)) {
        throw new RuntimeException('Unerwartetes Format.');
    }
    return $daten;
}
```

Ha mégis szükség van bizonyos osztályokra, nevezze meg őket egyenként az `allowed_classes`-ban, ahelyett hogy mindet engedélyezné. A kulcsnak a szerverkonfigurációba vagy egy secret-tárolóba kell tartoznia, és egy incidens után meg kell újítani.

### A meglévő adatok fokozatos átállítása JSON-ra

A kialakult alkalmazásokban a szerializált értékek gyakran évekig az adatbázisban vannak. Az egy lépésben végzett átállítás ilyenkor kockázatos. Egy átmenet vált be: az alkalmazás mindkét formátumot olvassa, de már csak JSON-t ír. Egy régi érték olvasásakor egyszer kicsomagolja az `allowed_classes => false` beállítással, és azonnal JSON-ként visszaírja. Egy idő után a legtöbb bejegyzés át van állítva, a maradékot pedig egy egyszeri szkript elvégzi.

Az átmenet alatt naplózza, milyen gyakran olvassák még a régi formátumot, és azt is, ha az aláírások nem egyeznek. Az ilyen kudarcok manipulációs kísérletekre utalhatnak, és a felügyeletbe tartoznak. Csak ha régi formátum már nem fordul elő, távolítsa el az `unserialize()` ágat teljesen a kódból.

## Rejtett deszerializáció: munkamenetek, gyorsítótárak és fájlútvonalak

Nem minden deszerializáció látszik a saját kódban. Ellenőrizze ezeket a helyeket is:

- **Munkamenetek:** A PHP a session-adatokat automatikusan szerializálja. Amíg a támadók nem tudják írni a session-fájlokat, ez nem kritikus. A weboldalankénti külön session-útvonalakat a [Munkamenetek védelme PHP-ban](https://phpsos.de/hu/ratgeber/session-sicherheit-php/) útmutató írja le.
- **Session-szerializáló:** A [CVE-2026-115560](https://phpsos.de/hu/php2shell/cve-2026-115560/)-ra vonatkozó közlemény egy szokatlan konfigurációt érint, amelyben a `serialize_handler` értékét futásidőben `ini_set()`-tel állítják át, és a session upload progress aktív. A php.net szerinti megoldás: `session.upload_progress.enabled=0` a php.ini-ben vagy az FPM-poolban, utána a workerek újraindítása.
- **Gyorsítótárak és várakozási sorok:** A Redis, a Memcached vagy a szerializált értékeket tartalmazó adatbázistáblák csak annyira biztonságosak, mint a hozzájuk vezető hozzáférés. Nem szabad nyitva lenniük a hálózat felé.
- **Fájlfüggvények bemenetekből származó útvonalakkal:** A fájlfüggvényeknek soha ne adjon át a kérésből származó útvonalakat. Az olyan stream wrapperek, mint a `phar://`, különben váratlan feldolgozást válthatnak ki. A fájlnevek engedélylistája megbízhatóbban véd bármilyen szűrésnél.
- **Függőségek:** Az ismert sebezhetőségekkel rendelkező könyvtárak bővítik a támadó lehetőségeit. Tartsa őket naprakészen, ahogy a [Composer-függőségek ellenőrzése résekre](https://phpsos.de/hu/ratgeber/composer-abhaengigkeiten-pruefen/) útmutató leírja.

## Kockázatos helyek keresése a kódban

Egy első leltár egy egyszerű kereséssel sikerül. Nem változtat a rendszeren, és megmutatja az összes hívást a `vendor` könyvtáron kívül:

```bash
grep -rn --include='*.php' 'unserialize(' /var/www/projekt \
  | grep -v '/vendor/'
```

Minden találatot három kérdéssel értékeljen: Honnan származnak az adatok? Megváltoztathatja őket egy felhasználó? Be van állítva az `allowed_classes`? A cookie-kból, a `$_GET`-ből, a `$_POST`-ból, a `$_REQUEST`-ből vagy külső interfészekről származó bemenetekkel rendelkező találatok elsőbbséget élveznek. Cserélje őket JSON-ra, és tesztelje az átállítást, mielőtt kigördíti.

Egy további támpont a böngészőben van. A szerializált PHP-adatoknak tipikus felépítésük van típusazonosítókkal és hosszadatokkal. Ha ilyen értékeket talál a saját weboldala cookie-iban, rejtett űrlapmezőiben vagy paramétereiben, az alkalmazás szerializált adatokat adott át a látogatónak, és valószínűleg visszavárja őket. Éppen ezeket a helyeket kell ellenőrizni.

A vezetőségnek elég egy egyszerű kérdés a fejlesztőknek vagy az ügynökségnek: „Dolgoz fel az alkalmazásunk valahol kívülről érkező szerializált adatokat, és ha igen, hogyan vannak védve?“ Egy világos válasz lelőhelyekkel jó jel. Egy kitérő válasz ok arra, hogy ellenőriztesse az alkalmazást.

## Hogyan segít konkrétan a PHP SOS?

- Átvizsgáljuk a kódját idegen adatokkal végzett deszerializáció után, és minden leletet az elérhetőség és a hatás szerint értékelünk.
- Konkrét átállításokat javasolunk JSON-ra vagy védett hívásokra, és a fejlesztőit végigkísérjük a megvalósításban.
- Ellenőrizzük a függőségeket ismert sebezhetőségek szempontjából, és dokumentáljuk az állapotot.
- Kívánságra az alkalmazást egy [biztonsági audit és penetrációs teszt](https://phpsos.de/hu/leistungen/sicherheitsaudit-penetrationstest/) keretében függetlenül ellenőriztetjük.


## Gyakori kérdések

**Az unserialize() a PHP-ban alapvetően nem biztonságos?**  
Nem olyan adatokra, amelyeket csak a saját alkalmazása hoz létre, és senki sem változtathat meg. Veszélyessé akkor válik, ha felhasználók vagy harmadik felek befolyásolhatják a bemenetet, például cookie-kon, űrlapmezőkön vagy külső interfészeken keresztül.

**Elég védelemnek az allowed_classes => false?**  
Megakadályozza tetszőleges objektumok létrehozását, és ezzel lezárja a legfontosabb támadási utat. Kívülről érkező bemenetekhez ennek ellenére a JSON a jobb választás, mert az elemző egyszerűbb, és nem rekonstruál objektumokat.

**Segít a könyvtárak frissítése a deszerializációs támadások ellen?**  
Részben. A támadások gyakran olyan függőségekből származó osztályokat használnak, amelyek egy objektum megsemmisítésekor vagy felébresztésekor műveleteket hajtanak végre. Az aktuális csomagok lezárják az ismert láncokat, a tényleges ok azonban az unserialize-hívás idegen adatokkal.

**Van köze a PHP2Shellnek a deszerializációhoz?**  
A két fő rés a PHP kéréskezelésében van. A CVE-2026-115560-ra vonatkozó közlemény ezzel szemben a munkamenet-szerializáció szokatlan konfigurációját érinti. A megoldás ott a session.upload_progress.enabled=0.

## Források

- [OWASP Cheat Sheet Series (Deserialization)](https://cheatsheetseries.owasp.org/)
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [php.net: biztonsági közlemények](https://www.php.net/)
