Dabartinė padėtis: PHP2Shell. Du kritiniai PHP pažeidžiamumai (CVSS 9,2) leidžia vykdyti kenkėjišką kodą be prisijungimo. Pataisos nuo 2026-10-21.Ką dabar daryti →

Server-Side Request Forgery (SSRF) PHP prevencija

Kaip kūrėjai užkerta kelią, kad PHP programa svetimų žmonių vardu nekreiptųsi į vidines sistemas: leidžiamųjų sąrašai, protokolų apribojimas, išspręsto adreso tikrinimas ir tinklo ribos.

Būsena 5 min. skaitymoSaugus programavimas

Trumpai: SSRF PHP užkertate kelią taip, kad jūsų programa kreiptųsi tik į adresus, esančius fiksuotame leidžiamųjų sąraše, tik per HTTPS ir nesekdama nukreipimų. Išspręstas IP adresas tikrinamas pagal privačius ir rezervuotus intervalus ir tada ryšiui užfiksuojamas. Ugniasienė išeinančiam srautui pasirūpina, kad vidinės sistemos net ir kodo klaidos atveju liktų nepasiekiamos.

Kai jūsų serveris siunčia užklausas svetimiems

Nuorodų peržiūros pokalbyje, produkto paveikslėlio importas pagal URL, webhook partnerių sistemoms, srautų (feed) skaitytuvas CMS: daugelis PHP programų kreipiasi į adresus, kuriuos nurodė naudotojas. Tai naudinga funkcija ir kartu durys į vidų.

Su Server-Side Request Forgery, trumpai SSRF, užpuolikas privers programą išsiųsti užklausą jo pasirinktam tikslui. Esmė: užklausa ateina iš paties serverio. Todėl ji pasiekia sistemas, kurios iš išorės užrakintos, pavyzdžiui, duomenų bazes, administravimo sąsajas vidiniame tinkle, tarnybas, klausančias tik localhost, ar debesies teikėjų metaduomenų tarnybas.

2021 m. OWASP Top 10 SSRF buvo atskira kategorija. PHP projektuose spraga dažnai atsiranda ten, kur kažkas greitai sukūrė funkciją „pridėti paveikslėlį pagal URL“.

SSRF PHP: kurios funkcijos kreipiasi į adresus

Adresų kviečia ne tik cURL. Į šias vietas verta atkreipti dėmesį:

Funkcija ar sritis Kodėl svarbu
cURL (curl_exec()) dažniausias kelias, galimi daugelis protokolų
file_get_contents(), fopen(), copy() su URL naudoja URL apvalkalus (wrapper), jei aktyvus allow_url_fopen
getimagesize() ir paveikslėlių bibliotekos gali įkelti nuotolinius failus
XML apdorojimas, SOAP klientai tam tikromis aplinkybėmis kraunami išoriniai ištekliai
HTTP bibliotekos kaip Guzzle remiasi cURL arba srautais, tos pačios taisyklės

Jei jūsų programai nereikia atidaryti nuotolinių failų per failų funkcijas, išjunkite allow_url_fopen serverio pusėje. Giminingą temą, failų įtraukimą pagal kelius iš užklausos, nagrinėja vadovas Local ir Remote File Inclusion prevencija.

Gynyba penkiais žingsniais

OWASP rekomenduoja priemonių derinį, kurias pavienes galima apeiti, bet kartu jos laiko:

  1. Leidžiamųjų sąrašas vietoj laisvo URL: geriausia, kad naudotojas rinktųsi tik iš žinomų tikslų arba nurodytų tik identifikatorių, o adresą programa sudarytų pati.
  2. Leisti tik HTTPS: cURL išjungti kitus protokolus kaip file, gopher ar ftp, taip pat nukreipimams.
  3. Nesekti nukreipimų: kitaip leidžiamas adresas gali nukreipti į vidinį tikslą.
  4. Patikrinti ir užfiksuoti išspręstą adresą: išspręsti pagrindinio kompiuterio vardą, patikrinti IP pagal privačius, loopback ir link-local intervalus ir ryšiui naudoti būtent šį IP. Kitaip antras DNS sprendimas gali pateikti kitą tikslą.
  5. Apriboti tinklą: žiniatinklio serveris į išorę gali pasiekti tik tuos tikslus, kurių jam reikia.

Saugus šablonas su cURL

Toliau pateiktas pavyzdys įgyvendina 1–4 žingsnius IPv4. Pagrindinių kompiuterių vardai ir eiga yra pavyzdžiai; IPv6 galioja tos pačios patikros.

<?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;
}

Keletas detalių svarbu. gethostbyname() klaidos atveju grąžina pagrindinio kompiuterio vardą; vėlesnė IP patikra tai sučiumpa. Vėliavėlės FILTER_FLAG_NO_PRIV_RANGE ir FILTER_FLAG_NO_RES_RANGE, pasak PHP vadovo, be kita ko, atmeta intervalus 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8 ir 169.254.0.0/16. Nuo PHP 8.2 yra ir FILTER_FLAG_GLOBAL_RANGE, leidžianti tik globaliai galiojančius adresus. CURLOPT_RESOLVE pasirūpina, kad cURL naudotų būtent patikrintą adresą, o pagrindinio kompiuterio vardas ir sertifikato patikra išliktų.

Dar du dalykai riboja, ką užpuolikas sužino iš SSRF spragos. Nekeiskite pakviesto tikslo atsakymų ir klaidų pranešimų nefiltruotų naudotojui: jau skirtumas tarp „ryšys atmestas“ ir „laiko riba viršyta“ išduoda, kokios vidinės tarnybos egzistuoja. Ir apribokite atsakymo trukmę bei dydį, kad funkcija netiktų savo serverio perkrovimui. Webhook adresams, kuriuos klientai įrašo patys, geriausia siųsti iš eilės, o ne vykstant užklausai.

Svarbu

Jei jūsų programai tikrai reikia kviesti savavališkus adresus, pavyzdžiui, nuorodų peržiūroms, iškelkite šią funkciją į atskirą tarnybą be prieigos prie vidinio tinklo. Leidžiamųjų sąrašas tada neįmanomas, o tinklo atskyrimas tuo svarbesnis.

Tinklo lygmuo kaip saugumo tinklas

Kodo patikros gali turėti spragų, pavyzdžiui, kai dvi bibliotekos URL išskaido skirtingai. OWASP pataria tokius neatitikimus traktuoti kaip atmetimą ir papildomai apriboti tinklo lygmenyje. Žiniatinklio serveriui į išorę dažniausiai reikia tik kelių tikslų: paketų šaltinių, mokėjimo ir siuntų paslaugų teikėjų, pašto relay, tam tikrų sąsajų.

Ugniasienė išeinančiam srautui padeda dvigubai. Ji sustabdo SSRF užklausas į vidinį tinklą ir apsunkina po įsilaužimo, pavyzdžiui, per nepataisytą PHP versiją, papildomų įrankių parsisiuntimą. Kaip sudaryti taisykles, aprašo Ugniasienė žiniatinklio serveriui: atverti tik reikalingus prievadus. Kokius ryšius serveris iš tikrųjų užmezga, parodo Serverio išeinančių ryšių patikra.

Debesies aplinkose prie to priklauso sutvirtintas metaduomenų tarnybos variantas. OWASP AWS atveju nurodo perėjimą prie IMDSv2 ir IMDSv1 išjungimą.

SSRF paieška esamame kode

Greitas įėjimas yra vietų paieška, kuriose kreipimosi funkcijos gauna reikšmes iš užklausos:

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"

Radiniai yra patikros užduotys. Ypač kruopščiai peržiūrėkite funkcijas, kuriomis naudojasi administratoriai: importus, webhook nustatymus, papildinių atnaujinimų patikras.

Lengvai praleidžiami PDF generatoriai, paverčiantys HTML su įterptais paveikslėliais ar stiliaus lentelėmis dokumentais. Jei dalis šio HTML kilusi iš naudotojo įvesties, pavyzdžiui, sąskaitose su laisvai pasirenkamu logotipu, generatorius gali kviesti naudotojo nustatytus adresus. Ten patikrinkite nuotolinių išteklių įkėlimo nustatymus ir išjunkite jį, jei nereikalingas.

Kaip PHP SOS padeda konkrečiai?

  • Randame visas vietas, kuriose jūsų programa kviečia adresus, taip pat papildiniuose ir bibliotekose.
  • Sukuriame centrinę kvietimo funkciją su leidžiamųjų sąrašu, protokolų apribojimu ir IP patikra.
  • Nustatome išeinančio srauto taisykles ir apsaugome metaduomenų tarnybas debesies aplinkose.
  • Įgyvendinimą patikriname iš išorės ir dokumentuojame leidžiamus tikslus.

Nepriklausomą jūsų programos patikrą aprašo Saugumo auditas ir įsiskverbimo testas.

Dažni klausimai

Kurios PHP funkcijos gali būti išnaudotos SSRF?

Visos, kurios kreipiasi į adresą iš naudotojo įvesties: cURL, file_get_contents ir fopen su URL apvalkalais (wrapper), paveikslėlių ir XML funkcijos, kraunančios nuotolinius failus, taip pat bibliotekos webhook, srautams (feed) ar nuorodų peržiūroms.

Ar pakanka užblokuoti vidinius IP adresus?

Vien to ne. OWASP uždraudimo sąrašus vadina lengvai apeinamais ir rekomenduoja leidžiamųjų sąrašus. Be to, programa turi naudoti būtent tą adresą, kurį patikrino, ir negali sekti nukreipimų.

Kodėl SSRF debesyje ypač kritiška?

Debesies teikėjai instancijoms suteikia vidines metaduomenų tarnybas, per kurias kartais galima gauti prisijungimo duomenis. Jei programa gali ten siųsti užklausas, užpuolikas per ją gali pasiekti šiuos duomenis. Teikėjai siūlo sutvirtintus šių tarnybų variantus, kuriuos reikėtų įjungti.

Ką duoda ugniasienė išeinančiam srautui?

Ji apriboja, kokius tikslus serveris apskritai gali pasiekti. Net jei kodo patikra nepavyksta, vidinės sistemos lieka nepasiekiamos. Be to, po įsilaužimo ji apsunkina kenkėjiško kodo parsisiuntimą ir duomenų nutekėjimą.

Šaltiniai

Skubus kontaktas

Kiekviena valanda svarbi. Parašykite mums dabar.

Trumpai aprašykite sistemą, PHP versiją ir pastebėjimus. Mes atsakysime, išsiaiškinsime padėtį ir dirbsime nuotoliu, kol incidentas bus užbaigtas ir dokumentuotas.

Skubi pagalba