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 →

XML External Entities (XXE) novēršana PHP

Kā izstrādātāji PHP droši apstrādā XML: libxml noklusējuma uzvedība, riskantas opcijas, piemēram, LIBXML_NOENT, aizsardzība ar entity loader un LIBXML_NO_XXE, kā arī tipiskas slēptas XML ieejas.

Aktuāls uz 5 min lasīšanas laiksDroša izstrāde

Īsi sakot: XXE PHP novērš, ielādējot XML no svešiem avotiem bez opcijām LIBXML_NOENT, LIBXML_DTDLOAD un LIBXML_DTDVALID, noraidot dokumentus ar savu DTD un iestatot entity loader, kas atsaka ārējus resursus. Kopš libxml 2.9.0 PHP entītijas pēc noklusējuma vairs neaizstāj, tāpēc libxml_disable_entity_loader() kopš PHP 8.0 ir novecojusi. No PHP 8.4 ar libxml 2.13 papildus pieejama LIBXML_NO_XXE.

Sena ievainojamība, kas nepazūd

XML External Entities, saīsināti XXE, daudziem izstrādātājiem šķiet nokārtota tēma. PHP ar modernām libxml versijām ārējo entītiju ielādi ir izslēdzis pēc noklusējuma, un vecā aizsardzības funkcija ar PHP 8.0 tika atzīmēta kā novecojusi. Tomēr XXE ievainojamības pārbaudēs turpina parādīties.

Iemesls gandrīz vienmēr ir kāda no trim situācijām: kāds iestatījis opciju, lai atrisinātu importa problēmu, un tādējādi atkal ieslēdzis entītiju aizstāšanu. Bibliotēka to dara iekšēji. Vai arī lietojumprogramma darbojas vecā sistēmā, kuras PHP būvēts ar ļoti vecu libxml.

XXE ir bīstams, jo XML parsētājs pie tam ielādē saturu, kas dokumentā tikai norādīts: lokālus failus vai adreses tīklā. Iespējamās sekas ir konfigurācijas failu nolasīšana, pieprasījumi uz iekšējām sistēmām līdzīgi kā SSRF gadījumā un servera pārslogošana.

Kas spēkā kopš libxml 2.9 un PHP 8.0

PHP rokasgrāmata situāciju apraksta šādi: no libxml 2.9.0 entītiju aizstāšana ir pēc noklusējuma izslēgta. Ārējās entītijas tāpēc vairs nav speciāli jāizslēdz, ja vien iekšējās entītiju atsauces nav jāatrisina ar noteiktām opcijām. No tā izriet šis pārskats:

Opcija Iedarbība Risks ar svešu XML
LIBXML_NOENT aizstāj entītijas saskaņā ar rokasgrāmatu var atvieglot XXE uzbrukumus
LIBXML_DTDLOAD ielādē ārējo apakškopu aktivizē ārējo entītiju ielādi
LIBXML_DTDVALID validē pret DTD var atvieglot XXE uzbrukumus
LIBXML_NONET aizliedz tīkla piekļuvi ielādes laikā aizsargājoša papildu opcija
LIBXML_NO_XXE izslēdz ārējās entītijas aizstāšanas laikā aizsargājoša, no PHP 8.4 un libxml 2.13.0
LIBXML_PARSEHUGE noņem parsētāja iekšējās robežas atvieglo pārslogošanu, tikai uzticamiem datiem

LIBXML_NOENT maldinošais nosaukums ir pazīstama lamatas: tas izklausās pēc „nav entītiju", bet rada pretējo.

Izstrādātājiem tas nozīmē: riskanta nav XML ielāde pati par sevi, bet katra vieta, kas apzināti maina noklusējuma uzvedību. Šo konstanšu meklēšana kodā tāpēc ir ātrākais ceļš uz pirmo novērtējumu, vēl pirms jebkuras darbietilpīgas pārbaudes.

XXE droša novēršana PHP: DOMDocument paraugs

Turpmākais piemērs apvieno vairākus aizsardzības slāņus. Tas iestata entity loader, kas atsaka katru ārējo resursu, ielādē bez riskantām opcijām un noraida dokumentus ar savu DTD:

<?php
declare(strict_types=1);

function ladeFremdesXml(string $xml): DOMDocument
{
    // Ārējos resursus principā atteikt
    libxml_set_external_entity_loader(
        static fn (?string $public, string $system, array $context) => null
    );

    $optionen = LIBXML_NONET;
    if (defined('LIBXML_NO_XXE')) {
        $optionen |= LIBXML_NO_XXE;
    }

    $vorher = libxml_use_internal_errors(true);
    $dom = new DOMDocument();
    $ok = $dom->loadXML($xml, $optionen);
    libxml_use_internal_errors($vorher);

    if (!$ok) {
        throw new InvalidArgumentException('XML ungültig.');
    }
    if ($dom->doctype !== null) {
        throw new InvalidArgumentException('Dokumente mit DTD werden nicht angenommen.');
    }
    return $dom;
}

Saskaņā ar PHP rokasgrāmatu atgriežamā vērtība null loader bloķē ārējā resursa ielādi. OWASP norāda, ka nepietiek null nodot tieši libxml_set_external_entity_loader(); vajadzīga funkcija, kas atgriež null. SimpleXML un XMLReader ir spēkā tās pašas opcijas. Kur vien iespējams, OWASP iesaka DTD noraidīt pilnībā.

Padoms

Ja datu formātu varat noteikt paši, apmaiņai starp savām sistēmām JSON parasti ir vienkāršāka izvēle. Svešiem formātiem, piemēram, SAML vai Office failiem, XML paliek neizbēgams.

Slēpto XML ieeju atrašana

Daudzas lietojumprogrammas apstrādā vairāk XML, nekā domā to izstrādātāji. Izejiet cauri šim sarakstam:

  1. Saskarnes: SOAP klienti un serveri, XML-RPC, maksājumu un piegādes pakalpojumi ar XML atbildēm.
  2. Pieteikšanās: vienotā pieteikšanās (SSO) ar SAML balstās uz XML dokumentiem, kas nāk no ārpuses.
  3. Importi: produktu dati, barotnes, vietnes kartes, katalogu formāti.
  4. Augšupielādes: SVG attēli ir XML; Office formāti, piemēram, DOCX un XLSX, iekšēji sastāv no XML failiem.
  5. Bibliotēkas: Composer pakotnes dokumentiem, tabulām vai SAML, kas iekšēji lieto libxml.

Kodā palīdz divas meklēšanas:

grep -rnE "LIBXML_(NOENT|DTDLOAD|DTDVALID|PARSEHUGE)" src/ vendor/ --include="*.php"
grep -rnE "(loadXML|simplexml_load_(string|file)|XMLReader|->load\()" src/ --include="*.php"

Atradumi vendor/ nav iemesls panikai, bet gan pamats pārbaudīt bibliotēkas versiju un drošības paziņojumus.

SVG augšupielādēs XXE ir tikai viens no vairākiem riskiem, jo SVG faili var saturēt arī skriptus. Ja jūsu lietojumprogrammai šis formāts nav obligāti vajadzīgs, vispār neatļaujiet to augšupielādēm. Citādi SVG apstrādājiet tikai ar iepriekš minēto drošo paraugu un failus piegādājiet tā, lai pārlūks iekšā esošos skriptus neizpilda.

Ņemiet vērā arī kļūdu ziņojumus. Ja lietojumprogramma libxml ziņojumus atdod lietotājiem nefiltrētus, tajos var būt apstrādātā satura daļas. Kļūdām jāiet žurnālā, lietotājs saņem vispārīgu ziņojumu; iepriekšējā piemērā libxml_use_internal_errors(true) nodrošina, ka brīdinājumi nenonāk izvadē. Ierobežojiet arī saņemto XML dokumentu izmēru, pirms parsētājs tos vispār redz.

Vecās sistēmas: kad standarta aizsardzības nav

Aizsardzība ar noklusējuma uzvedību ir atkarīga no libxml versijas, ar kuru PHP būvēts. Kura versija darbojas, parāda php -r 'echo LIBXML_DOTTED_VERSION, PHP_EOL;' komandrindā vai phpinfo() izvade aizsargātā vidē. Pārbaudiet vērtību katrai PHP versijai serverī, jo CLI un tīmekļa serveris var izmantot dažādus būvējumus. Konteineru attēli nes savu libxml; tur pārbaudiet darbojošamies konteinerā, nevis resursdatorā.

Īpaši skartas ir sistēmas, kas tāpat darbojas ar vecām PHP versijām. PHP 8.1 un vecākām versijām pēc PHP2Shell oficiālu PHP projekta atjauninājumu vairs nav; ko tas nozīmē, apraksta PHP 8.1 un vecākas: kas tagad spēkā. Veca sistēma ar novecojušu libxml un atvērtām interpretatora ievainojamībām jāaizsargā ne tikai kodā, bet jāmigrē. Radniecīgus riskus svešu datu apstrādē apraksta Nedroša deserializācija PHP, iekšējo mērķu atvēršanu Server-Side Request Forgery novēršana PHP.

Kā PHP SOS palīdz konkrēti?

  • Mēs atrodam visas vietas, kur jūsu lietojumprogramma un tās bibliotēkas apstrādā XML no svešiem avotiem.
  • Mēs noņemam riskantas parsētāja opcijas un ieviešam centrālu, nodrošinātu ielādes funkciju.
  • Mēs pārbaudām libxml un PHP versijas visos serveros un vecām sistēmām plānojam migrāciju.
  • Mēs testējam izmaiņas ar nekaitīgiem pārbaudes dokumentiem un dokumentējam rezultātu.

Savas programmatūras pārbaudi apraksta pakalpojums drošības audits un penetrācijas tests.

Biežāk uzdotie jautājumi

Vai PHP lietojumprogrammas kopš PHP 8 ir automātiski aizsargātas pret XXE?

Noklusējuma gadījumā lielā mērā jā, jo libxml no versijas 2.9.0 entītijas vairs neaizstāj. Aizsardzība tomēr atkrīt, tiklīdz kods iestata opcijas, piemēram, LIBXML_NOENT, LIBXML_DTDLOAD vai LIBXML_DTDVALID, vai PHP ir būvēts ar ļoti vecu libxml versiju.

Vai libxml_disable_entity_loader vēl jāizsauc?

Nē. Funkcija kopš PHP 8.0 ir novecojusi, jo ārējo entītiju ielāde pēc noklusējuma ir izslēgta. Papildu aizsardzībai PHP rokasgrāmata iesaka libxml_set_external_entity_loader un no PHP 8.4 ar atbilstošu libxml konstanti LIBXML_NO_XXE.

Kur mana lietojumprogramma vispār apstrādā XML?

Bieži negaidītās vietās: SOAP saskarnēs, vienotā pieteikšanās (SSO) ar SAML, RSS barotnēs, vietnes kartēs, produktu importos, SVG augšupielādēs un Office failos, kas iekšēji sastāv no XML. XML var apstrādāt arī bibliotēkas, un tas nav redzams paša kodā.

Kas ir Billion Laughs uzbrukums?

Dokuments ar ligzdotām entītijām, kas atrisinot milzīgi pieaug un patērē atmiņu un skaitļošanas laiku. Tas pieder tai pašai saimei kā XXE. Aizsardzību dod entītiju aizstāšanas izslēgšana un dokumentu ar savu DTD noraidīšana.

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