Na kratko: SSRF v PHP preprečite tako, da vaša aplikacija pridobiva samo naslove s stalnega dovoljenega seznama, izključno prek HTTPS in brez sledenja preusmeritvam. Razrešeni naslov IP se preveri proti zasebnim in rezerviranim območjem in nato za povezavo zadrži. Požarni zid za odhodni promet poskrbi, da notranji sistemi ostanejo nedosegljivi tudi ob napaki v kodi.
Kadar lasten strežnik pošilja zahteve za tujce
Predogledi povezav v klepetu, uvoz slike izdelka prek URL, webhooki k partnerskim sistemom, bralnik virov v CMS: številne aplikacije PHP pridobivajo naslove, ki jih je vnesel uporabnik. To je uporabna funkcija in hkrati vrata navznoter.
Pri Server-Side Request Forgery, na kratko SSRF, napadalec aplikacijo prisili, da pošlje zahtevo na cilj po njegovi izbiri. Poanta: zahteva prihaja od samega strežnika. Tako doseže sisteme, ki so od zunaj zaprti, na primer baze podatkov, upravljalske vmesnike v notranjem omrežju, storitve, ki poslušajo samo na localhost, ali storitve z metapodatki ponudnikov oblaka.
V OWASP Top 10 iz leta 2021 je bil SSRF lastna kategorija. V projektih PHP se ranljivost pogosto pojavi tam, kjer je nekdo hitro zgradil funkcijo „dodaj sliko prek URL“.
SSRF v PHP: katere funkcije pridobivajo naslove
Naslove ne pridobiva samo cURL. Na naslednja mesta bodite pozorni:
| Funkcija ali področje | Zakaj je pomembno |
|---|---|
cURL (curl_exec()) |
najpogostejša pot, mogočih je veliko protokolov |
file_get_contents(), fopen(), copy() z URL |
uporabljajo ovojnice URL, če je allow_url_fopen aktiven |
getimagesize() in knjižnice za slike |
lahko naložijo oddaljene datoteke |
| obdelava XML, odjemalci SOAP | včasih naložijo zunanje vire |
| knjižnice HTTP, kot je Guzzle | temeljijo na cURL ali tokovih, enaka pravila |
Če vaša aplikacija ne potrebuje odpiranja oddaljenih datotek prek datotečnih funkcij, allow_url_fopen izklopite na strežniku. Sorodno temo, vključevanje datotek prek poti iz zahteve, obravnava vodnik Preprečevanje Local in Remote File Inclusion.
Obramba v petih korakih
OWASP priporoča kombinacijo ukrepov, ki bi jih vsakega posebej lahko obšli, skupaj pa držijo:
- Dovoljeni seznam namesto prostega URL: Najbolje je, da uporabnik izbira samo med znanimi cilji ali navede le oznako, naslov pa aplikacija sestavi sama.
- Dovolite samo HTTPS: druge protokole, kot so
file,gopheraliftp, v cURL izključite, tudi za preusmeritve. - Ne sledite preusmeritvam: dovoljen naslov sicer lahko preusmeri na notranji cilj.
- Razrešeni naslov preverite in zadržite: razrešite ime gostitelja, IP preverite proti zasebnim območjem, območju povratne zanke (loopback) in območjem link-local ter za povezavo uporabite natanko ta IP. Sicer lahko drugo razreševanje DNS vrne drug cilj.
- Omejite omrežje: spletni strežnik sme navzven doseči samo cilje, ki jih potrebuje.
Varen vzorec s cURL
Naslednji primer izvaja korake od 1 do 4 za IPv4. Imena gostiteljev in potek so primeri; za IPv6 veljajo enaka preverjanja.
<?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;
}
Nekaj podrobnosti je pomembnih. gethostbyname() ob napaki vrne ime gostitelja; naknadno preverjanje IP to ujame. Zastavici FILTER_FLAG_NO_PRIV_RANGE in FILTER_FLAG_NO_RES_RANGE po priročniku PHP med drugim izključita območja 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8 in 169.254.0.0/16. Od PHP 8.2 obstaja dodatno FILTER_FLAG_GLOBAL_RANGE, ki dopušča samo globalno veljavne naslove. CURLOPT_RESOLVE poskrbi, da cURL uporabi natanko preverjeni naslov, ime gostitelja in preverjanje potrdila pa ostaneta.
Dve nadaljnji točki omejita, kaj se napadalec nauči iz ranljivosti SSRF. Odgovorov in sporočil o napakah pridobljenega cilja ne vračajte uporabniku nefiltrirano: že razlika med „povezava zavrnjena“ in „časovna omejitev“ izda, katere notranje storitve obstajajo. In omejite trajanje ter velikost odgovora, da funkcija ni uporabna za preobremenitev lastnega strežnika. Webhooke na naslove, ki jih stranke vnesejo same, najbolje pošiljajte iz čakalne vrste in ne med tekočo zahtevo.
Če mora vaša aplikacija res pridobivati poljubne naslove, na primer za predoglede povezav, to funkcijo prestavite v ločeno storitev brez dostopa do notranjega omrežja. Dovoljeni seznam takrat ni mogoč, ločitev omrežja pa je toliko pomembnejša.
Omrežna raven kot varnostna mreža
Preverjanja v kodi imajo lahko vrzeli, na primer če dve knjižnici URL razčlenita različno. OWASP svetuje, da se take neskladnosti obravnavajo kot zavrnitev, in dodatno omejitev na omrežni ravni. Spletni strežnik navzven večinoma potrebuje le nekaj ciljev: vire paketov, ponudnike plačil in dostave, poštni relay, določene vmesnike.
Požarni zid za odhodni promet pomaga dvojno. Ustavi zahteve SSRF v notranje omrežje in po vdoru, na primer prek nepopravljene različice PHP, oteži nalaganje nadaljnjih orodij. Kako zgradite pravila, opisuje Požarni zid za spletni strežnik: odprite samo potrebna vrata. Katere povezave strežnik dejansko vzpostavlja, pokaže Preverjanje odhodnih povezav strežnika.
V okoljih oblaka sodi zraven utrjena različica storitve z metapodatki. OWASP za AWS navaja prehod na IMDSv2 in izklop IMDSv1.
Iskanje SSRF v obstoječi kodi
Hiter začetek je iskanje mest, kjer funkcije za pridobivanje prejmejo vrednosti iz zahteve:
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"
Zadetki so naloge za preverjanje. Še posebej temeljito poglejte funkcije, ki jih uporabljajo skrbniki: uvoze, nastavitve webhookov, preverjanja posodobitev vtičnikov.
Zlahka se spregledajo generatorji PDF, ki HTML z vključenimi slikami ali slogovnimi listi pretvorijo v dokumente. Če del tega HTML izvira iz uporabniških vnosov, na primer pri računih s prosto izbranim logotipom, generator morda pridobiva naslove, ki jih določi uporabnik. Tam preverite nastavitve za nalaganje oddaljenih virov in jih izklopite, če jih ne potrebujete.
Kako konkretno pomaga PHP SOS?
- Poiščemo vsa mesta, kjer vaša aplikacija pridobiva naslove, tudi v vtičnikih in knjižnicah.
- Zgradimo osrednjo funkcijo za pridobivanje z dovoljenim seznamom, omejitvijo protokolov in preverjanjem IP.
- Določimo pravila za odhodni promet in zaščitimo storitve z metapodatki v okoljih oblaka.
- Izvedbo preverimo od zunaj in dokumentiramo dovoljene cilje.
Neodvisen pregled vaše aplikacije opisuje Varnostni pregled in penetracijski test.
Pogosta vprašanja
Katere funkcije PHP je mogoče zlorabiti za SSRF?
Vse, ki pridobivajo naslov iz uporabniških vnosov: cURL, file_get_contents in fopen z ovojnicami URL, funkcije za slike in XML, ki nalagajo oddaljene datoteke, ter knjižnice za webhooke, vire (feed) ali predoglede povezav.
Ali zadošča blokiranje notranjih naslovov IP?
Samo po sebi ne. OWASP črne sezname označuje kot lahko obvozne in priporoča dovoljene sezname. Poleg tega mora aplikacija uporabiti natanko naslov, ki ga je preverila, in ne sme slediti preusmeritvam.
Zakaj je SSRF v oblaku posebej kritičen?
Ponudniki oblaka instancam dajejo na voljo notranje storitve z metapodatki, prek katerih je deloma mogoče pridobiti dostopne podatke. Če lahko aplikacija tja pošilja zahteve, napadalec prek nje te podatke doseže. Ponudniki ponujajo utrjene različice teh storitev, ki naj bodo vklopljene.
Kaj prinese požarni zid za odhodni promet?
Omeji, katere cilje strežnik sploh lahko doseže. Tudi če preverjanje v kodi odpove, notranji sistemi ostanejo nedosegljivi. Poleg tega po vdoru oteži nalaganje škodljive kode in odtekanje podatkov.