Aktuális helyzet: PHP2Shell. Két kritikus PHP-rés (CVSS 9,2) lehetővé teszi kártékony kód futtatását bejelentkezés nélkül. Javítások 2026. 10. 21. óta.Mi a teendő most →

Server-Side Request Forgery (SSRF) megelőzése PHP-ban

Hogyan akadályozzák meg a fejlesztők, hogy egy PHP-alkalmazás idegenek megbízásából belső rendszereket kérdezzen le: engedélyezési listák, protokollkorlátozás, a feloldott cím ellenőrzése és hálózati határok.

Állapot 6 perc olvasási időBiztonságos fejlesztés

Röviden: Az SSRF-et PHP-ban úgy előzi meg, hogy az alkalmazása csak olyan címeket hív le, amelyek egy rögzített engedélyezési listán szerepelnek, kizárólag HTTPS-en, átirányítások követése nélkül. A feloldott IP-címet a privát és fenntartott tartományokkal szemben ellenőrzi, majd a kapcsolathoz rögzíti. A kimenő forgalom tűzfala gondoskodik arról, hogy a belső rendszerek a kód hibája esetén is elérhetetlenek maradjanak.

Amikor a saját szerver kérdez idegenek helyett

Linkelőnézetek egy chatben, egy termékkép importálása URL-lel, webhookok partnerrendszerekhez, egy hírolvasó a CMS-ben: sok PHP-alkalmazás hív le olyan címeket, amelyeket egy felhasználó adott meg. Ez hasznos funkció, és egyben egy ajtó befelé.

A Server-Side Request Forgery, röviden SSRF esetén a támadó rávesz egy alkalmazást, hogy a választása szerinti célra küldjön kérést. A csattanó: a kérés magától a szervertől érkezik. Így olyan rendszereket ér el, amelyek kívülről le vannak zárva, például adatbázisokat, a belső hálózat adminisztrációs felületeit, csak a localhoston figyelő szolgáltatásokat vagy a felhőszolgáltatók metaadat-szolgáltatásait.

Az OWASP Top 10 2021-es kiadásában az SSRF külön kategória volt. A PHP-projektekben a rés gyakran ott bukkan fel, ahol valaki gyorsan összeütött egy „kép hozzáadása URL-lel” funkciót.

SSRF PHP-ban: mely függvények hívnak le címeket

Nem csak a cURL hív le címeket. A következő helyekre figyeljen:

Függvény vagy terület Miért releváns
cURL (curl_exec()) a leggyakoribb út, sok protokoll lehetséges
file_get_contents(), fopen(), copy() URL-lel URL-wrappereket használnak, ha az allow_url_fopen aktív
getimagesize() és képkönyvtárak távoli fájlokat tölthetnek be
XML-feldolgozás, SOAP-kliensek adott esetben külső erőforrásokat töltenek be
HTTP-könyvtárak, például a Guzzle cURL-ra vagy stream-ekre épülnek, ugyanazok a szabályok

Ha az alkalmazásának nem kell távoli fájlokat fájlfüggvényekkel megnyitnia, kapcsolja ki az allow_url_fopen beállítást a szerver oldalán. Egy rokon témát, a kérésből származó útvonalakkal történő fájlbeágyazást, a Local és Remote File Inclusion megelőzése útmutató tárgyalja.

A védelem öt lépésben

Az OWASP olyan intézkedések kombinációját ajánlja, amelyek egyenként megkerülhetők lennének, együtt azonban elbírnak:

  1. Engedélyezési lista szabad URL helyett: a legjobb, ha a felhasználó csak ismert célok közül választ, vagy csak egy azonosítót ad meg, és az alkalmazás maga építi fel a címet.
  2. Csak HTTPS engedélyezése: a cURL-ban kizárni az olyan protokollokat, mint a file, a gopher vagy az ftp, az átirányításoknál is.
  3. Átirányításokat nem követni: egy engedélyezett cím különben belső célra irányíthat át.
  4. A feloldott cím ellenőrzése és rögzítése: feloldani a hosztnevet, az IP-t ellenőrizni a privát, loopback és link-local tartományokkal szemben, és pontosan ezt az IP-t használni a kapcsolathoz. Különben egy második DNS-feloldás más célt adhat.
  5. A hálózat korlátozása: a webszerver kifelé csak azokat a célokat érheti el, amelyekre szüksége van.

Biztonságos minta cURL-lel

A következő példa az 1–4. lépést valósítja meg IPv4-re. A hosztnevek és a folyamat példák; IPv6-ra ugyanazok az ellenőrzések érvényesek.

<?php
declare(strict_types=1);

function ladeVonPartner(string $url): string
{
    $teile = parse_url($url);
    if (!is_array($teile) || ($teile['scheme'] ?? '') !== 'https'
        || isset($teile['user']) || isset($teile['pass']) || isset($teile['port'])) {
        throw new InvalidArgumentException('Adresse nicht erlaubt.');
    }

    $host = strtolower($teile['host'] ?? '');
    $erlaubt = ['api.partner.example', 'bilder.partner.example'];
    if (!in_array($host, $erlaubt, true)) {
        throw new InvalidArgumentException('Ziel nicht erlaubt.');
    }

    $ip = gethostbyname($host);
    $oeffentlich = filter_var($ip, FILTER_VALIDATE_IP,
        FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
    if ($oeffentlich === false) {
        throw new RuntimeException('Ziel löst auf eine nicht erlaubte Adresse auf.');
    }

    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER  => true,
        CURLOPT_FOLLOWLOCATION  => false,
        CURLOPT_PROTOCOLS       => CURLPROTO_HTTPS,
        CURLOPT_REDIR_PROTOCOLS => CURLPROTO_HTTPS,
        CURLOPT_RESOLVE         => [$host . ':443:' . $ip],
        CURLOPT_CONNECTTIMEOUT  => 3,
        CURLOPT_TIMEOUT         => 10,
    ]);
    $antwort = curl_exec($ch);
    if ($antwort === false) {
        throw new RuntimeException('Abruf fehlgeschlagen.');
    }
    return $antwort;
}

Néhány részlet fontos. A gethostbyname() hiba esetén a hosztnevet adja vissza; az ezt követő IP-ellenőrzés ezt kivédi. A FILTER_FLAG_NO_PRIV_RANGE és a FILTER_FLAG_NO_RES_RANGE flag a PHP kézikönyve szerint többek között a 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8 és 169.254.0.0/16 tartományokat zárja ki. A PHP 8.2 óta létezik emellett a FILTER_FLAG_GLOBAL_RANGE, amely csak globálisan érvényes címeket enged. A CURLOPT_RESOLVE gondoskodik arról, hogy a cURL pontosan az ellenőrzött címet használja, miközben a hosztnév és a tanúsítvány-ellenőrzés megmarad.

Két további pont korlátozza, mit tanul a támadó egy SSRF-résből. A lehívott cél válaszait és hibaüzeneteit ne adja vissza szűretlenül a felhasználónak: már a „kapcsolat elutasítva” és az „időtúllépés” közötti különbségtétel is elárulja, mely belső szolgáltatások léteznek. És korlátozza a válasz futási idejét és méretét, hogy a funkció ne legyen alkalmas a saját szerver túlterhelésére. Azokat a webhookokat, amelyek az ügyfelek által maguk megadott címekre mennek, a legjobb egy sorból küldeni, nem a folyamatban lévő kérés közben.

Fontos

Ha az alkalmazásának valóban tetszőleges címeket kell lehívnia, például linkelőnézetekhez, szervezze ki ezt a funkciót egy különálló szolgáltatásba, amelynek nincs hozzáférése a belső hálózathoz. Engedélyezési lista ekkor nem lehetséges, a hálózati szétválasztás annál fontosabb.

A hálózati szint mint biztonsági háló

A kódellenőrzéseknek lehetnek hézagai, például ha két könyvtár másképp bont fel egy URL-t. Az OWASP azt tanácsolja, hogy az ilyen következetlenségeket elutasításként kezeljék, és ezenkívül hálózati szinten is korlátozzanak. Egy webszervernek kifelé többnyire csak kevés célra van szüksége: csomagforrásokra, fizetési és szállítmányozási szolgáltatókra, levelezési relére, bizonyos interfészekre.

A kimenő forgalom tűzfala kétszeresen segít. Megállítja az SSRF-kéréseket a belső hálózatba, és egy betörés után, például egy nem patchelt PHP-verzión keresztül, megnehezíti további eszközök utántöltését. Hogyan építse fel a szabályokat, azt a Tűzfal webszerverekhez: csak a szükséges portokat nyitni írja le. Hogy a szerver ténylegesen milyen kapcsolatokat épít fel, azt a Egy szerver kimenő kapcsolatainak ellenőrzése mutatja.

Felhős környezetekben a metaadat-szolgáltatás keményített változata is hozzátartozik. Az OWASP az AWS-nél az IMDSv2-re való áttérést és az IMDSv1 kikapcsolását említi.

Az SSRF felderítése a meglévő kódban

Gyors belépő a keresés azokra a helyekre, ahol a lehívó függvények a kérésből kapnak értékeket:

grep -rnE "(curl_init|file_get_contents|fopen|getimagesize|copy)\s*\(" src/ --include="*.php" | grep -E '\$_(GET|POST|REQUEST)|\$url'
grep -rn "CURLOPT_FOLLOWLOCATION" src/ --include="*.php"

A találatok ellenőrzési feladatok. Különösen alaposan nézze meg azokat a funkciókat, amelyeket az adminok használnak: importok, webhook-beállítások, bővítmények frissítés-ellenőrzései.

Könnyen elkerülik a figyelmet a PDF-generátorok, amelyek beágyazott képekkel vagy stíluslapokkal rendelkező HTML-t alakítanak dokumentumokká. Ha ennek a HTML-nek egy része felhasználói bemenetből származik, például szabadon választható logójú számláknál, a generátor adott esetben olyan címeket hív le, amelyeket a felhasználó határoz meg. Ott ellenőrizze a távoli erőforrások betöltésének beállításait, és kapcsolja ki, ha nincs rá szükség.

Hogyan segít konkrétan a PHP SOS?

  • Megkeressük az összes helyet, ahol az alkalmazása címeket hív le, a bővítményekben és a könyvtárakban is.
  • Központi lehívó függvényt építünk engedélyezési listával, protokollkorlátozással és IP-ellenőrzéssel.
  • Szabályokat állapítunk meg a kimenő forgalomra, és védjük a metaadat-szolgáltatásokat felhős környezetekben.
  • Kívülről ellenőrizzük a megvalósítást, és dokumentáljuk az engedélyezett célokat.

Az alkalmazás független ellenőrzését a biztonsági audit és penetrációs teszt írja le.

Gyakori kérdések

Mely PHP-függvényekkel lehet visszaélni SSRF-hez?

Mindegyikkel, amely felhasználói bemenetből származó címet hív le: cURL, file_get_contents és fopen URL-wrapperekkel, távoli fájlokat betöltő kép- és XML-függvények, valamint a webhookokhoz, feedekhez vagy linkelőnézetekhez használt könyvtárak.

Elég a belső IP-címek letiltása?

Önmagában nem. Az OWASP a tiltólistákat megkerülhetőnek nevezi, és engedélyezési listákat ajánl. Ezenkívül az alkalmazásnak pontosan azt a címet kell használnia, amelyet ellenőrzött, és nem követhet átirányításokat.

Miért különösen kritikus az SSRF a felhőben?

A felhőszolgáltatók a példányok számára belső metaadat-szolgáltatásokat biztosítanak, amelyeken keresztül részben hozzáférési adatok is lehívhatók. Ha egy alkalmazás kéréseket küldhet oda, a támadó rajta keresztül elérheti ezeket az adatokat. A szolgáltatók ezeknek a szolgáltatásoknak keményített változatait kínálják, amelyeket aktiválni kell.

Mit ad egy tűzfal a kimenő forgalomhoz?

Korlátozza, hogy a szerver egyáltalán mely célokat érheti el. Még ha egy ellenőrzés a kódban cserbenhagy is, a belső rendszerek elérhetetlenek maradnak. Ezenkívül egy betörés után megnehezíti a kártékony kód utántöltését és az adatok kiáramlását.

Források

Azonnali kapcsolat

Minden óra számít. Írjon nekünk most.

Ismertesse röviden a rendszert, a PHP-verziót és a megfigyelését. Jelentkezünk, tisztázzuk a helyzetet, és távolról dolgozunk, amíg az incidens le nem zárul és dokumentálva nem lesz.

Azonnali segítség