Aktuel situation: PHP2Shell. To kritiske PHP-sårbarheder (CVSS 9,2) tillader skadelig kode uden login. Rettelser siden 21.10.2026.Hvad der skal gøres nu →

Forhindr Server-Side Request Forgery (SSRF) i PHP

Hvordan udviklere forhindrer, at en PHP-applikation på vegne af fremmede forespørger interne systemer: tilladelseslister, protokolbegrænsning, kontrol af den opløste adresse og grænser i netværket.

Status 5 min. læsetidSikker udvikling

Kort sagt: SSRF i PHP forhindrer I ved, at jeres applikation kun henter adresser, der står på en fast tilladelsesliste, udelukkende via HTTPS og uden at følge omdirigeringer. Den opløste IP-adresse kontrolleres mod private og reserverede områder og fastholdes derefter til forbindelsen. En firewall for udgående trafik sørger for, at interne systemer forbliver utilgængelige, selv ved en fejl i koden.

Når den egen server sender forespørgsler for fremmede

Linkforhåndsvisninger i en chat, import af et produktbillede via URL, webhooks til partnersystemer, en feedreader i CMS'et: Mange PHP-applikationer henter adresser, som en bruger har angivet. Det er en nyttig funktion og samtidig en dør indad.

Ved Server-Side Request Forgery, kort SSRF, får en angriber applikationen til at sende en forespørgsel til et mål efter eget valg. Pointen: Forespørgslen kommer fra serveren selv. Den når dermed systemer, der er spærret udefra, f.eks. databaser, administrationsgrænseflader i det interne netværk, tjenester, der kun lytter på localhost, eller cloududbyderes metadatatjenester.

I OWASP Top 10 fra 2021 var SSRF en egen kategori. I PHP-projekter dukker sårbarheden ofte op dér, hvor nogen hurtigt har bygget en "tilføj billede via URL"-funktion.

SSRF i PHP: Hvilke funktioner henter adresser

Det er ikke kun cURL, der henter adresser. Følgende steder bør I have øje for:

Funktion eller område Hvorfor relevant
cURL (curl_exec()) hyppigste vej, mange protokoller mulige
file_get_contents(), fopen(), copy() med URL bruger URL-wrappers, når allow_url_fopen er aktiv
getimagesize() og billedbiblioteker kan indlæse fjernfiler
XML-behandling, SOAP-klienter indlæser under visse omstændigheder eksterne ressourcer
HTTP-biblioteker som Guzzle bygger på cURL eller streams, samme regler

Hvis jeres applikation ikke behøver at åbne fjernfiler via filfunktioner, slår I allow_url_fopen fra på serversiden. Et beslægtet emne, indlæsning af filer via stier fra forespørgslen, behandler vejledningen Forhindr Local og Remote File Inclusion.

Forsvaret i fem trin

OWASP anbefaler en kombination af foranstaltninger, som hver for sig kunne omgås, men tilsammen bærer:

  1. Tilladelsesliste i stedet for fri URL: Bedst vælger brugeren kun blandt kendte mål, eller angiver blot en identifikator, og applikationen bygger selv adressen.
  2. Tillad kun HTTPS: Udeluk andre protokoller som file, gopher eller ftp i cURL, også ved omdirigeringer.
  3. Følg ingen omdirigeringer: En tilladt adresse kan ellers omdirigere til et internt mål.
  4. Kontrollér og fastholdt den opløste adresse: Opløs værtsnavnet, kontrollér IP'en mod private, loopback- og link-local-områder og brug netop denne IP til forbindelsen. Ellers kan en anden DNS-opløsning levere et andet mål.
  5. Begræns netværket: Webserveren må udadtil kun nå de mål, den har brug for.

Et sikkert mønster med cURL

Følgende eksempel gennemfører trin 1 til 4 for IPv4. Værtsnavne og forløb er eksempler; for IPv6 gælder de samme kontroller.

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

Nogle detaljer er vigtige. gethostbyname() returnerer ved en fejl værtsnavnet; den efterfølgende IP-kontrol opfanger det. Flagene FILTER_FLAG_NO_PRIV_RANGE og FILTER_FLAG_NO_RES_RANGE udelukker ifølge PHP-manualen blandt andet områderne 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8 og 169.254.0.0/16. Siden PHP 8.2 findes desuden FILTER_FLAG_GLOBAL_RANGE, som kun tillader globalt gyldige adresser. CURLOPT_RESOLVE sørger for, at cURL bruger netop den kontrollerede adresse, mens værtsnavn og certifikatkontrol bevares.

To yderligere punkter begrænser, hvad en angriber lærer af en SSRF-sårbarhed. Giv ikke svar og fejlmeddelelser fra det hentede mål ufiltreret tilbage til brugeren: Allerede skelnen mellem "forbindelse afvist" og "timeout" afslører, hvilke interne tjenester der findes. Og begræns køretid og svarets størrelse, så funktionen ikke kan bruges til at overbelaste den egen server. Webhooks til adresser, som kunder selv indtaster, sender I bedst fra en kø og ikke under den igangværende forespørgsel.

Vigtigt

Skal jeres applikation virkelig hente vilkårlige adresser, f.eks. til linkforhåndsvisninger, så udlæg denne funktion til en separat tjeneste uden adgang til det interne netværk. En tilladelsesliste er så ikke mulig, netværksadskillelsen desto vigtigere.

Netværksniveauet som sikkerhedsnet

Kodekontroller kan have huller, f.eks. når to biblioteker opdeler en URL forskelligt. OWASP råder til at behandle sådanne uoverensstemmelser som afvisning og desuden at begrænse på netværksniveau. En webserver har udadtil som regel kun brug for få mål: pakkekilder, betalings- og forsendelsesudbydere, mailrelay, bestemte grænseflader.

En firewall for udgående trafik hjælper dobbelt. Den stopper SSRF-forespørgsler ind i det interne netværk, og den besværliggør efter et indbrud, f.eks. via en upatchet PHP-version, indlæsning af yderligere værktøjer. Hvordan I opbygger reglerne, beskriver Firewall til webservere: Åbn kun nødvendige porte. Hvilke forbindelser en server faktisk opbygger, viser Kontrollér en servers udgående forbindelser.

I cloudmiljøer hører den hærdede variant af metadatatjenesten med. OWASP nævner for AWS overgangen til IMDSv2 og afbrydelsen af IMDSv1.

Opspor SSRF i eksisterende kode

Et hurtigt udgangspunkt er søgningen efter steder, hvor hentefunktioner får værdier fra forespørgslen:

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"

Fund er kontroloplæg. Særligt grundigt bør I se på funktioner, som administratorer bruger: importer, webhook-indstillinger, opdateringskontroller af plugins.

Let at overse er PDF-generatorer, der omsætter HTML med indlejrede billeder eller stylesheets til dokumenter. Stammer en del af dette HTML fra brugerinput, f.eks. ved fakturaer med frit valgt logo, henter generatoren under visse omstændigheder adresser, som brugeren bestemmer. Kontrollér dér indstillingerne for indlæsning af fjernressourcer, og slå det fra, hvis det ikke er nødvendigt.

Hvordan hjælper PHP SOS konkret?

  • Vi finder alle steder, hvor jeres applikation henter adresser, også i plugins og biblioteker.
  • Vi bygger en central hentefunktion med tilladelsesliste, protokolbegrænsning og IP-kontrol.
  • Vi fastlægger regler for udgående trafik og beskytter metadatatjenester i cloudmiljøer.
  • Vi kontrollerer gennemførelsen udefra og dokumenterer tilladte mål.

En uafhængig kontrol af jeres applikation beskriver Sikkerhedsaudit og penetrationstest.

Ofte stillede spørgsmål

Hvilke PHP-funktioner kan misbruges til SSRF?

Alle, der henter en adresse fra brugerinput: cURL, file_get_contents og fopen med URL-wrappers, billed- og XML-funktioner, der indlæser fjernfiler, samt biblioteker til webhooks, feeds eller linkforhåndsvisninger.

Er det nok at spærre interne IP-adresser?

Ikke alene. OWASP betegner spærrelister som sårbare over for omgåelse og anbefaler tilladelseslister. Desuden skal applikationen bruge netop den adresse, den har kontrolleret, og må ikke følge omdirigeringer.

Hvorfor er SSRF særligt kritisk i skyen?

Cloududbydere stiller interne metadatatjenester til rådighed for instanser, hvorigennem adgangsdata delvist kan hentes. Kan en applikation sende forespørgsler dertil, kan en angriber nå disse data via den. Udbyderne tilbyder hærdede varianter af disse tjenester, som bør være aktiveret.

Hvad giver en firewall for udgående trafik?

Den begrænser, hvilke mål serveren overhovedet kan nå. Selv hvis en kontrol i koden svigter, forbliver interne systemer så utilgængelige. Desuden besværliggør den efter et indbrud indlæsning af skadelig kode og udsivning af data.

Kilder

Akut kontakt

Hver time tæller. Skriv til os nu.

Beskriv kort system, PHP-version og observation. Vi vender tilbage, afklarer situationen og arbejder på afstand, indtil hændelsen er afsluttet og dokumenteret.

Akut hjælp