Situația actuală: PHP2Shell. Două vulnerabilități critice PHP (CVSS 9.2) permit cod malițios fără autentificare. Patchuri din 21.10.2026.Ce este de făcut acum →

Prevenirea Server-Side Request Forgery (SSRF) în PHP

Cum împiedică dezvoltatorii ca o aplicație PHP să interogheze sisteme interne în numele unor terți: liste de permisiuni, restricționarea protocolului, verificarea adresei rezolvate și limite în rețea.

Stadiu 6 min de cititDezvoltare sigură

Pe scurt: Preveniți SSRF în PHP făcând ca aplicația dumneavoastră să apeleze doar adrese aflate pe o listă fixă de permisiuni, exclusiv prin HTTPS, fără a urma redirecționări. Adresa IP rezolvată este verificată față de intervalele private și rezervate și apoi fixată pentru conexiune. Un firewall pentru traficul de ieșire face ca sistemele interne să rămână inaccesibile chiar și în cazul unei erori din cod.

Când propriul server face cereri pentru terți

Previzualizări de linkuri într-un chat, importul unei imagini de produs prin URL, webhook-uri către sisteme partenere, un cititor de feed-uri în CMS: multe aplicații PHP apelează adrese indicate de un utilizator. Aceasta este o funcție utilă și, în același timp, o ușă spre interior.

La Server-Side Request Forgery, pe scurt SSRF, un atacator determină aplicația să trimită o cerere către o țintă aleasă de el. Miezul: cererea provine de la serverul însuși. Ea ajunge astfel la sisteme blocate din exterior, de exemplu baze de date, interfețe de administrare din rețeaua internă, servicii care ascultă doar pe localhost sau serviciile de metadate ale furnizorilor de cloud.

În OWASP Top 10 din 2021, SSRF a fost o categorie separată. În proiectele PHP, vulnerabilitatea apare adesea acolo unde cineva a construit repede o funcție „adaugă imagine prin URL”.

SSRF în PHP: ce funcții apelează adrese

Nu doar cURL apelează adrese. Iată locurile pe care ar trebui să le aveți în vedere:

Funcție sau domeniu De ce este relevant
cURL (curl_exec()) Cea mai frecventă cale, sunt posibile multe protocoale
file_get_contents(), fopen(), copy() cu URL Folosesc wrappere URL, dacă allow_url_fopen este activ
getimagesize() și bibliotecile de imagini Pot încărca fișiere la distanță
Procesarea XML, clienți SOAP Încarcă uneori resurse externe
Biblioteci HTTP precum Guzzle Se bazează pe cURL sau pe stream-uri, aceleași reguli

Dacă aplicația dumneavoastră nu trebuie să deschidă fișiere la distanță prin funcții de fișiere, dezactivați allow_url_fopen pe server. O temă înrudită, includerea de fișiere prin căi din cerere, o tratează ghidul Prevenirea Local și Remote File Inclusion.

Apărarea în cinci pași

OWASP recomandă o combinație de măsuri care, luate individual, ar putea fi ocolite, dar împreună rezistă:

  1. Listă de permisiuni în loc de URL liber: Cel mai bine, utilizatorul alege doar dintre ținte cunoscute sau indică doar un identificator, iar aplicația construiește singură adresa.
  2. Permiteți doar HTTPS: Excludeți în cURL alte protocoale precum file, gopher sau ftp, inclusiv pentru redirecționări.
  3. Nu urmați redirecționări: O adresă permisă poate altfel redirecționa către o țintă internă.
  4. Verificați și fixați adresa rezolvată: Rezolvați numele de host, verificați IP-ul față de intervalele private, loopback și link-local și folosiți exact acest IP pentru conexiune. Altfel, o a doua rezolvare DNS poate returna o altă țintă.
  5. Limitați rețeaua: Serverul web are voie să atingă spre exterior doar țintele de care are nevoie.

Un model sigur cu cURL

Exemplul următor implementează pașii 1 până la 4 pentru IPv4. Numele de host și desfășurarea sunt exemple; pentru IPv6 se aplică aceleași verificări.

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

Câteva detalii sunt importante. gethostbyname() returnează numele de host în caz de eroare; verificarea IP care urmează prinde acest caz. Flagurile FILTER_FLAG_NO_PRIV_RANGE și FILTER_FLAG_NO_RES_RANGE exclud, potrivit manualului PHP, printre altele intervalele 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8 și 169.254.0.0/16. Începând cu PHP 8.2 există suplimentar FILTER_FLAG_GLOBAL_RANGE, care permite doar adrese valide global. CURLOPT_RESOLVE face ca cURL să folosească exact adresa verificată, în timp ce numele de host și verificarea certificatului se păstrează.

Alte două puncte limitează ce află un atacator dintr-o vulnerabilitate SSRF. Nu returnați utilizatorului nefiltrate răspunsurile și mesajele de eroare ale țintei apelate: chiar și distincția dintre „conexiune refuzată” și „depășire de timp” trădează ce servicii interne există. Și limitați durata și dimensiunea răspunsului, pentru ca funcția să nu poată servi la suprasolicitarea propriului server. Webhook-urile către adrese pe care clienții și le introduc singuri le trimiteți cel mai bine dintr-o coadă și nu în timpul cererii în curs.

Important

Dacă aplicația dumneavoastră chiar trebuie să apeleze adrese arbitrare, de exemplu pentru previzualizări de linkuri, externalizați această funcție într-un serviciu separat, fără acces la rețeaua internă. O listă de permisiuni nu este atunci posibilă, iar separarea rețelei este cu atât mai importantă.

Nivelul de rețea ca plasă de siguranță

Verificările din cod pot avea lacune, de exemplu când două biblioteci descompun diferit o URL. OWASP sfătuiește să tratați asemenea neconcordanțe ca respingere și să limitați suplimentar la nivel de rețea. Un server web are spre exterior, de regulă, nevoie de puține ținte: surse de pachete, furnizori de plăți și expediere, releu de e-mail, anumite interfețe.

Un firewall pentru traficul de ieșire ajută dublu. Oprește cererile SSRF spre rețeaua internă și îngreunează după o intruziune, de exemplu printr-o versiune PHP nepatch-uită, reîncărcarea altor instrumente. Cum construiți regulile descrie Firewall pentru serverul web: deschideți doar porturile necesare. Ce conexiuni inițiază efectiv un server arată Verificarea conexiunilor de ieșire ale unui server.

În mediile cloud face parte din aceasta varianta întărită a serviciului de metadate. OWASP indică pentru AWS trecerea la IMDSv2 și dezactivarea IMDSv1.

Depistarea SSRF în codul existent

O intrare rapidă este căutarea locurilor în care funcțiile de apelare primesc valori din cerere:

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"

Rezultatele sunt sarcini de verificare. Priviți deosebit de atent funcțiile folosite de administratori: importuri, setări de webhook, verificări de actualizare ale pluginurilor.

Ușor de trecut cu vederea sunt generatoarele de PDF care transformă HTML cu imagini sau foi de stil încorporate în documente. Dacă o parte din acest HTML provine din introduceri ale utilizatorului, de exemplu la facturi cu logo la alegere, generatorul apelează uneori adrese stabilite de utilizator. Verificați acolo setările pentru încărcarea resurselor la distanță și dezactivați-o dacă nu este necesară.

Cum ajută PHP SOS concret?

  • Găsim toate locurile în care aplicația dumneavoastră apelează adrese, inclusiv în pluginuri și biblioteci.
  • Construim o funcție centrală de apelare, cu listă de permisiuni, restricționarea protocolului și verificarea IP.
  • Stabilim reguli pentru traficul de ieșire și protejăm serviciile de metadate din mediile cloud.
  • Verificăm implementarea din exterior și documentăm țintele permise.

O verificare independentă a aplicației dumneavoastră descrie Audit de securitate și test de penetrare.

Întrebări frecvente

Ce funcții PHP pot fi folosite abuziv pentru SSRF?

Toate cele care apelează o adresă preluată din introducerile utilizatorului: cURL, file_get_contents și fopen cu wrappere URL, funcții pentru imagini și XML care încarcă fișiere la distanță, precum și biblioteci pentru webhook-uri, feed-uri sau previzualizări de linkuri.

Este suficient să blochez adresele IP interne?

Singure, nu. OWASP descrie listele de blocare ca ușor de ocolit și recomandă liste de permisiuni. În plus, aplicația trebuie să folosească exact adresa pe care a verificat-o și nu are voie să urmeze redirecționări.

De ce este SSRF deosebit de critic în cloud?

Furnizorii de cloud pun la dispoziția instanțelor servicii interne de metadate, prin care pot fi uneori obținute date de acces. Dacă o aplicație poate trimite cereri acolo, un atacator poate ajunge prin ea la aceste date. Furnizorii oferă variante întărite ale acestor servicii, care ar trebui activate.

Ce aduce un firewall pentru traficul de ieșire?

Limitează ce ținte poate atinge serverul, în general. Chiar dacă o verificare din cod eșuează, sistemele interne rămân atunci inaccesibile. În plus, îngreunează după o intruziune reîncărcarea de cod malițios și scurgerea de date.

Surse

Contact imediat

Fiecare oră contează. Scrieți-ne acum.

Descrieți pe scurt sistemul, versiunea PHP și ce ați observat. Ne vom face auziți, clarificăm situația și lucrăm la distanță până când incidentul este încheiat și documentat.

Ajutor imediat