Lühidalt: XXE-d hoiate PHP-s ära nii, et laadite võõrastest allikatest pärit XML-i ilma valikuteta LIBXML_NOENT, LIBXML_DTDLOAD ja LIBXML_DTDVALID, lükkate tagasi oma DTD-ga dokumendid ning seate Entity-Loaderi, mis keeldub välistest ressurssidest. libxml 2.9.0-st alates PHP entity'id vaikimisi enam ei asenda, seetõttu on libxml_disable_entity_loader() PHP 8.0-st vananenud. PHP 8.4-st koos libxml 2.13-ga on lisaks saadaval LIBXML_NO_XXE.
Vana auk, mis ei kao
XML External Entities ehk XXE loetakse paljude arendajate jaoks lahendatud teemaks. PHP on kaasaegsete libxml-i versioonidega väliste entity'de laadimise vaikimisi välja lülitanud ja vana kaitsefunktsioon märgiti PHP 8.0-ga vananenuks. Sellest hoolimata ilmuvad XXE-augud kontrollides edasi.
Põhjus peitub peaaegu alati ühes kolmest olukorrast: keegi on seadnud valiku impordiprobleemi lahendamiseks ja lülitanud sellega entity asendamise uuesti sisse. Teek teeb seda seespidiselt. Või töötab rakendus vanal süsteemil, mille PHP on ehitatud väga vana libxml-iga.
XXE on ohtlik, sest XML-parser laadib seejuures sisu, millele dokumendis ainult viidatakse: kohalikud failid või aadressid võrgus. Võimalikud tagajärjed on konfiguratsioonifailide väljalugemine, päringud sisesüsteemidele sarnaselt SSRF-iga ja serveri ülekoormamine.
Mis kehtib libxml 2.9 ja PHP 8.0 järel
PHP käsiraamat kirjeldab olukorda nii: libxml 2.9.0-st on entity'de asendamine vaikimisi välja lülitatud. Väliseid entity'id ei pea seetõttu enam eraldi välja lülitama, välja arvatud juhul, kui sisemised entity viited tuleb teatud valikutega lahendada. Sellest tuleneb see ülevaade:
| Valik | Mõju | Risk võõra XML-i puhul |
|---|---|---|
LIBXML_NOENT |
asendab entity'id | käsiraamatu kohaselt võib XXE-rünnakuid hõlbustada |
LIBXML_DTDLOAD |
laadib välise alamhulga | aktiveerib väliste entity'de laadimise |
LIBXML_DTDVALID |
valideerib DTD vastu | võib XXE-rünnakuid hõlbustada |
LIBXML_NONET |
keelab laadimisel võrguühendused | kaitsev lisavalik |
LIBXML_NO_XXE |
lülitab asendamisel välised entity'id välja | kaitsev, PHP 8.4-st ja libxml 2.13.0-st |
LIBXML_PARSEHUGE |
tühistab parseri sisemised piirid | hõlbustab ülekoormamist, ainult usaldusväärsete andmete jaoks |
LIBXML_NOENT eksitav nimi on tuntud lõks: see kõlab nagu „ei mingeid entity'id“, kuid toimib vastupidiselt.
Arendajatele tähendab see: riskantne ei ole XML-i laadimine iseenesest, vaid iga koht, mis vaikekäitumist teadlikult muudab. Nende konstantide otsing koodis on seetõttu kiireim tee esimese hinnanguni, enne iga töömahukat kontrolli.
XXE turvaline tõrje PHP-s: muster DOMDocumenti jaoks
Järgmine näide ühendab mitu kaitsekihti. See seab Entity-Loaderi, mis keeldub igast välisest ressursist, laeb ilma riskantsete valikuteta ja lükkab tagasi oma DTD-ga dokumendid:
<?php
declare(strict_types=1);
function ladeFremdesXml(string $xml): DOMDocument
{
// Väliseid ressursse põhimõtteliselt mitte lubada
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;
}
PHP käsiraamatu kohaselt blokeerib tagastusväärtus null loaderis välise ressursi laadimise. OWASP juhib tähelepanu, et ei piisa, kui anda null otse funktsioonile libxml_set_external_entity_loader(); vaja on funktsiooni, mis tagastab null. SimpleXML-i ja XMLReaderi puhul kehtivad samad valikud. Kus iganes võimalik, soovitab OWASP DTD-d täielikult tagasi lükata.
Kui saate andmevormingu ise määrata, on JSON oma süsteemide vaheliseks andmevahetuseks tavaliselt lihtsam valik. Võõraste vormingute, nagu SAML või Office-failid, puhul jääb XML vältimatuks.
Peidetud XML-sisendite leidmine
Paljud rakendused töötlevad rohkem XML-i, kui nende arendajad arvavad. Käige see nimekiri läbi:
- Liidesed: SOAP-kliendid ja -serverid, XML-RPC, makse- ja saatmisteenused XML-vastustega.
- Sisselogimine: SAML-iga ühekordne sisselogimine põhineb XML-dokumentidel, mis tulevad väljastpoolt.
- Impordid: tooteandmed, voogud, saidikaardid, kataloogivormingud.
- Üleslaadimised: SVG-pildid on XML; Office-vormingud, nagu DOCX ja XLSX, koosnevad seespidiselt XML-failidest.
- Teegid: Composer-paketid dokumentide, tabelite või SAML-i jaoks, mis kasutavad seespidiselt libxml-i.
Koodis aitavad kaks otsingut:
grep -rnE "LIBXML_(NOENT|DTDLOAD|DTDVALID|PARSEHUGE)" src/ vendor/ --include="*.php"
grep -rnE "(loadXML|simplexml_load_(string|file)|XMLReader|->load\()" src/ --include="*.php"
Leiud kaustas vendor/ ei ole põhjus paanikaks, kuid põhjus kontrollida teegi versiooni ja turvateateid.
SVG-üleslaadimiste puhul on XXE ainult üks mitmest riskist, sest SVG-failid võivad sisaldada ka skripte. Kui teie rakendus seda vormingut tingimata ei vaja, ärge lubage seda üleslaadimisteks üldse. Muul juhul töötlege SVG-d ainult ülaltoodud turvalise mustriga ja edastage failid nii, et brauser sisalduvaid skripte ei käivita.
Pöörake tähelepanu ka veateadetele. Kui rakendus tagastab libxml-i teated kasutajatele filtreerimata, võivad neis olla osad töödeldud sisust. Vead kuuluvad logisse, kasutaja saab üldise teate; ülaltoodud näites hoolitseb libxml_use_internal_errors(true) selle eest, et hoiatused väljundisse ei satuks. Piirake lisaks vastuvõetud XML-dokumentide suurust, enne kui parser neid üldse näeb.
Vanad süsteemid: millal vaikekaitse puudub
Vaikekäitumise kaitse sõltub libxml-i versioonist, millega PHP on ehitatud. Millist versiooni kasutatakse, näitab php -r 'echo LIBXML_DOTTED_VERSION, PHP_EOL;' käsureal või phpinfo() väljund kaitstud keskkonnas. Kontrollige väärtust iga PHP versiooni jaoks serveris, sest CLI ja veebiserver võivad kasutada erinevaid ehitusi. Konteineripildid toovad kaasa oma libxml-i; seal kontrollige töötavas konteineris, mitte hostis.
Eriti mõjutatud on süsteemid, mis niikuinii töötavad vanadel PHP versioonidel. PHP 8.1 ja vanemate jaoks ei ole pärast PHP2Shelli PHP projektilt enam ametlikke uuendusi; mida see tähendab, kirjeldab PHP 8.1 ja vanemad: mis nüüd kehtib. Vana süsteem aegunud libxml-i ja avatud interpretaatoriaukudega tuleks mitte ainult koodis kaitsta, vaid migreerida. Seotud riskid võõraste andmete töötlemisel kirjeldab Ebaturvaline deserialiseerimine PHP-s, sisemiste sihtkohtade päringuid Server-Side Request Forgery vältimine PHP-s.
Kuidas PHP SOS konkreetselt aitab?
- Me leiame kõik kohad, kus teie rakendus ja selle teegid töötlevad võõrastest allikatest pärit XML-i.
- Me eemaldame riskantsed parseri valikud ja ehitame sisse kesksed, kaitstud laadimisfunktsioonid.
- Me kontrollime libxml-i ja PHP versioone kõigis serverites ning planeerime vanade süsteemide puhul migratsiooni.
- Me testime muudatusi kahjutute kontrolldokumentidega ja dokumenteerime tulemuse.
Oma tarkvara kontrolli kirjeldab teenus Turvaaudit ja läbitungimistest.
Korduma kippuvad küsimused
Kas PHP-rakendused on PHP 8-st alates XXE eest automaatselt kaitstud?
Vaikejuhul suures osas, sest libxml ei asenda entity'id enam alates versioonist 2.9.0. Kaitse langeb aga ära, niipea kui kood seab valikuid nagu LIBXML_NOENT, LIBXML_DTDLOAD või LIBXML_DTDVALID või kui PHP on ehitatud väga vana libxml-i versiooniga.
Kas peaksin libxml_disable_entity_loader'it veel kutsuma?
Ei. Funktsioon on PHP 8.0-st vananenud, sest väliste entity'de laadimine on vaikimisi välja lülitatud. Lisakaitseks soovitab PHP käsiraamat funktsiooni libxml_set_external_entity_loader ning alates PHP 8.4-st sobiva libxml-iga konstanti LIBXML_NO_XXE.
Kus minu rakendus üldse XML-i töötleb?
Sageli ootamatutes kohtades: SOAP-liidesed, SAML-iga ühekordne sisselogimine, RSS-voogud, saidikaardid, tooteimpordid, SVG-üleslaadimised ja Office-failid, mis koosnevad seespidiselt XML-ist. Ka teegid võivad XML-i töödelda, ilma et see oleks oma koodis nähtav.
Mis on Billion-Laughs-rünnak?
Dokument pesastatud entity'dega, mis lahendamisel kasvab tohutult ning tarbib mälu ja arvutusaega. See kuulub samasse perekonda mis XXE. Kaitse pakuvad entity asendamise väljalülitamine ja oma DTD-ga dokumentide tagasilükkamine.