Aktuālā situācija: PHP2Shell. Divas kritiskas PHP ievainojamības (CVSS 9.2) ļauj izpildīt ļaunprātīgu kodu bez pieteikšanās. Ielāpi kopš 21.10.2026.Kas jādara tagad →

Nedroša deserializācija PHP: unserialize un drošība

unserialize() ar svešiem datiem sliktākajā gadījumā var novest pie koda izpildes. Kā to aizstāt ar JSON, ierobežot tur, kur tas jāatstāj, un atrast riskantās vietas kodā.

Aktuāls uz 5 min lasīšanas laiksRokasgrāmatas

Īsi: PHP unserialize drošībā ir vienkāršs noteikums: datus, kas nāk no ārpuses, nekad neapstrādāt ar unserialize(). Tā vietā izmantojiet JSON. Kur unserialize() no vecā koda jāatstāj, ierobežojiet to ar allowed_classes => false un datu īstumu pārbaudiet ar parakstu.

Kas ar unserialize() var noiet greizi

PHP ar serialize() var masīvus un objektus pārvērst rakstzīmju virknē un ar unserialize() tos atjaunot. Tas ir ērti, lai datus ievietotu sīkdatnēs, kešatmiņās vai datubāzes laukos. Problēma: unserialize() tā rezultātā veido arī jebkuru klašu objektus, kuras lietojumprogrammā var ielādēt.

Veidojot un vēlākais iznīcinot šādu objektu, PHP automātiski izsauc noteiktas metodes, piemēram, __wakeup(), __unserialize() vai __destruct(). Ja klasēs projektā vai bibliotēkās ir šādas metodes ar failu, datubāzes vai sistēmas darbībām, uzbrucējs tās ar manipulētiem datiem var izmantot citam mērķim. Speciālisti runā par PHP Object Injection. Atkarībā no esošajām klasēm ietekme sniedzas no atsevišķu failu dzēšanas līdz ļaunprātīga koda izpildei.

Netehniski apkopojot: viens pārdomāts izsaukums nepareizā vietā var ielaist uzbrucēju dziļi lietojumprogrammā. Šī ievainojamība tāpēc jau gadiem pieder pie OWASP Top 10 tēmām.

Drošā alternatīva: JSON nevis unserialize

Gandrīz visos gadījumos, kad dati nāk no ārpuses vai atstāj serveri, pareizā izvēle ir JSON. json_decode() veido tikai masīvus, skaitļus, rakstzīmju virknes un patiesuma vērtības, nevis paša klašu objektus.

<?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.');
    }

    // Pārņemt tikai zināmus laukus ar gaidītajiem tipiem
    return [
        'sprache' => in_array($daten['sprache'] ?? '', ['de', 'en'], true) ? $daten['sprache'] : 'de',
        'seiten'  => max(1, min(100, (int) ($daten['seiten'] ?? 20))),
    ];
}

Svarīga ir otrā daļa: arī JSON dati ir ievade. Pārņemiet tikai gaidītos laukus un pārbaudiet tipus un vērtību diapazonus, pirms ar tiem strādājat.

Ja unserialize nav izvairāms: allowed_classes un paraksts

Vecākās lietojumprogrammās serializēti dati bieži atrodas datubāzēs vai kešatmiņās, ko nevar pārslēgt uzreiz. Tad risku ierobežojat divos soļos. Pirmkārt, ar allowed_classes novēršat objektu veidošanu. Otrkārt, ar HMAC parakstu pārliecināties, ka dati patiešām nāk no jūsu lietojumprogrammas un ceļā nav mainīti.

<?php
declare(strict_types=1);

const SCHLUESSEL = 'aus-sicherer-konfiguration-laden'; // nekad koda repozitorijā

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;
}

Ja tomēr vajadzīgas noteiktas klases, nosauciet tās atsevišķi allowed_classes, nevis atļaujiet visas. Atslēgai jāatrodas servera konfigurācijā vai noslēpumu glabātuvē, un pēc incidenta tā jāatjauno.

Esošo datu pakāpeniska pārslēgšana uz JSON

Izaugušās lietojumprogrammās serializētas vērtības datubāzē bieži atrodas gadiem. Pārslēgšana vienā solī tad ir riskanta. Ir noderējusi pārejas shēma: lietojumprogramma lasa abus formātus, bet raksta tikai JSON. Nolasot vecu vērtību, tā vienreiz tiek izpakota ar allowed_classes => false un uzreiz atpakaļ ierakstīta kā JSON. Pēc kāda laika lielākā daļa ierakstu ir pārslēgti, un vienreizējs skripts nokārto pārējo.

Pārejas laikā protokolējiet, cik bieži vēl tiek lasīts vecais formāts, kā arī gadījumus, kad paraksti nesakrīt. Šādas neveiksmes var norādīt uz manipulāciju mēģinājumiem, un tām jābūt uzraudzībā. Tikai kad vecais formāts vairs neparādās, unserialize() atzaru no koda noņemiet pilnībā.

Slēpta deserializācija: sesijas, kešatmiņas un failu ceļi

Ne katra deserializācija ir redzama paša kodā. Pārbaudiet arī šīs vietas:

  • Sesijas: PHP sesiju datus serializē automātiski. Kamēr uzbrucēji nevar rakstīt sesiju failus, tas nav kritiski. Atsevišķus sesiju ceļus katrai vietnei apraksta ceļvedis Sesiju nodrošināšana PHP.
  • Sesiju serializētājs: Norāde par CVE-2026-115560 skar neparastu konfigurāciju, kurā serialize_handler izpildes laikā tiek pārslēgts ar ini_set() un ir aktīvs sesijas augšupielādes progress. Atvieglojums saskaņā ar php.net: session.upload_progress.enabled=0 failā php.ini vai FPM pūlā, pēc tam darbprocesu pārstartēšana.
  • Kešatmiņas un rindas: Redis, Memcached vai datubāzes tabulas ar serializētām vērtībām ir tik drošas, cik droša ir piekļuve tām. Tām nav jābūt atklāti tīklā.
  • Failu funkcijas ar ceļiem no ievades: Failu funkcijām nekad nenododiet ceļus no pieprasījuma. Stream wrapper, piemēram, phar://, citādi var izraisīt negaidītu apstrādi. Atļauju saraksts faila nosaukumiem šeit aizsargā uzticamāk nekā jebkāda filtrēšana.
  • Atkarības: Bibliotēkas ar zināmām ievainojamībām paplašina uzbrucēja iespējas. Uzturiet tās aktuālas, kā aprakstīts ceļvedī Composer atkarību pārbaude uz ievainojamībām.

Riskantu vietu atrašana kodā

Pirmo inventarizāciju var veikt ar vienkāršu meklēšanu. Tā sistēmā neko nemaina un parāda visus izsaukumus ārpus vendor direktorija:

grep -rn --include='*.php' 'unserialize(' /var/www/projekt \
  | grep -v '/vendor/'

Vērtējiet katru atradumu ar trim jautājumiem: no kurienes nāk dati? Vai lietotājs tos var mainīt? Vai allowed_classes ir iestatīts? Atradumi ar ievadi no sīkdatnēm, $_GET, $_POST, $_REQUEST vai ārējām saskarnēm ir prioritāri. Aizstājiet tos ar JSON un pārslēgšanu pārbaudiet, pirms to izvēršat.

Vēl viena norāde atrodas pārlūkā. Serializētiem PHP datiem ir tipiska uzbūve ar tipu apzīmējumiem un garuma norādēm. Ja šādas vērtības atrodat sīkdatnēs, slēptos veidlapu laukos vai savas vietnes parametros, lietojumprogramma serializētus datus ir nodevusi apmeklētājam un, visticamāk, gaida tos atpakaļ. Tieši šīs vietas jāpārbauda.

Vadībai pietiek ar vienkāršu jautājumu izstrādātājiem vai aģentūrai: „Vai mūsu lietojumprogramma kaut kur apstrādā serializētus datus, kas nāk no ārpuses, un ja jā, kā tie ir aizsargāti?“ Skaidra atbilde ar atrašanās vietām ir laba zīme. Izvairīga atbilde ir iemesls lietojumprogrammu ļaut pārbaudīt.

Kā PHP SOS palīdz konkrēti?

  • Pārmeklējam jūsu kodu uz deserializāciju ar svešiem datiem un vērtējam katru atradumu pēc sasniedzamības un ietekmes.
  • Piedāvājam konkrētas pārslēgšanas uz JSON vai nodrošinātiem izsaukumiem un atbalstām jūsu izstrādātājus īstenošanā.
  • Pārbaudām atkarības uz zināmām ievainojamībām un dokumentējam stāvokli.
  • Pēc vēlēšanās lietojumprogrammu ļaujam neatkarīgi pārbaudīt drošības audita un penetrācijas testa ietvaros.

Biežāk uzdotie jautājumi

Vai unserialize() PHP principā ir nedrošs?

Ne datiem, ko ģenerē tikai jūsu pašu lietojumprogramma un ko neviens nevar mainīt. Bīstami kļūst, tiklīdz lietotāji vai trešās personas var ietekmēt ievadi, piemēram, caur sīkdatnēm, veidlapu laukiem vai ārējām saskarnēm.

Vai allowed_classes => false kā aizsardzība pietiek?

Tas neļauj izveidot patvaļīgus objektus un tādējādi aizver svarīgāko uzbrukuma ceļu. Ārējai ievadei JSON tomēr ir labāka izvēle, jo parsētājs ir vienkāršāks un objektus neatjauno.

Vai bibliotēku atjaunināšana palīdz pret deserializācijas uzbrukumiem?

Daļēji. Uzbrukumi bieži izmanto atkarību klases, kas objekta iznīcināšanas vai pamodināšanas brīdī izpilda darbības. Aktuālas pakotnes aizver zināmās ķēdes, taču īstais cēlonis ir unserialize izsaukums ar svešiem datiem.

Vai PHP2Shell ir kāds sakars ar deserializāciju?

Abas galvenās ievainojamības ir PHP pieprasījumu apstrādē. Norāde par CVE-2026-115560 turpretī skar neparastu sesiju serializācijas konfigurāciju. Atvieglojums tur ir session.upload_progress.enabled=0.

Avoti

Tūlītējs kontakts

Katra stunda ir svarīga. Rakstiet mums tūlīt.

Īsi aprakstiet sistēmu, PHP versiju un novēroto. Mēs sazināsimies, noskaidrosim situāciju un strādāsim attālināti, līdz incidents ir slēgts un dokumentēts.

Tūlītēja palīdzība