# Server-Side Request Forgery (SSRF) megelőzése PHP-ban

> SSRF megelőzése PHP-ban: engedélyezési listák, csak HTTPS, nincs átirányítás, a feloldott IP ellenőrzése és a kimenő forgalom korlátozása. cURL-kóddal.

Forrás: https://phpsos.de/hu/blog/ssrf-in-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:** 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](https://phpsos.de/hu/ratgeber/lfi-rfi/) ú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
<?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](https://phpsos.de/hu/blog/firewall-fuer-webserver/) írja le. Hogy a szerver ténylegesen milyen kapcsolatokat épít fel, azt a [Egy szerver kimenő kapcsolatainak ellenőrzése](https://phpsos.de/hu/blog/ausgehende-verbindungen-pruefen/) 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:

```bash
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](https://phpsos.de/hu/leistungen/sicherheitsaudit-penetrationstest/) í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

- [OWASP Server-Side Request Forgery Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html)
- [PHP kézikönyv: szűrő-konstansok](https://www.php.net/manual/de/filter.constants.php)
- [PHP kézikönyv: cURL-konstansok](https://www.php.net/manual/de/curl.constants.php)
