Direct naar inhoud

Server-side request forgery (SSRF)

CWE-918OWASP A01:2025Bijgewerkt 3 oktober 20266 min leestijd

Server-side request forgery (SSRF) is een kwetsbaarheid waarbij een aanvaller uw server dwingt om verbindingen te maken naar adressen naar keuze. Zo bereikt hij interne systemen en clouddiensten die vanaf internet nooit toegankelijk zouden mogen zijn.

Server-side request forgery, kortweg SSRF, is een van de sluipendste webkwetsbaarheden: de aanvaller stuurt niet uw browser aan, maar uw eigen server. In deze uitleg leest u wat SSRF is, hoe zo’n aanval in de praktijk verloopt, wat een aanvaller ermee kan bereiken en hoe u uw applicatie ertegen dichttimmert.

Wat is server-side request forgery?

Server-side request forgery (SSRF) is een kwetsbaarheid waarbij een aanvaller uw server zover krijgt dat die namens hem verbindingen opzet naar een adres dat de aanvaller kiest. De applicatie denkt dat ze een legitiem verzoek doet, maar fungeert in werkelijkheid als doorgeefluik naar plekken die de aanvaller zelf nooit had mogen bereiken.

Vergelijk het met een receptionist die elk telefoonnummer belt dat een bezoeker op een briefje schrijft. De bezoeker staat buiten en komt het gebouw niet in, maar de receptionist zit binnen, en kan dus ook interne toestellen bellen. Vraagt de bezoeker om “toestel 1234, de kluiskamer”, dan belt de receptionist dat gedwee, want het staat immers op het briefje. SSRF misbruikt precies die vertrouwenspositie van de server binnen het netwerk.

Hoe werkt een SSRF-aanval?

SSRF ontstaat overal waar een applicatie een URL of adres uit gebruikersinvoer haalt en die vervolgens zelf ophaalt: een webhook, een “importeer via URL”-functie, een link-preview, een PDF-generator of een afbeeldingsproxy. Zolang die invoer niet wordt gecontroleerd, bepaalt de gebruiker naar welk adres de server verbinding maakt.

Kwetsbaar:

// Afbeeldingsproxy die klakkeloos elk opgegeven adres ophaalt
app.get('/fetch', async (req, res) => {
  const url = req.query.url;
  const response = await fetch(url);
  const body = await response.text();
  res.send(body);
});

Deze proxy haalt elk adres op dat in de queryparameter staat. Vraagt een aanvaller /fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/ op, dan bevraagt de server het metadata-endpoint van de cloudprovider en stuurt de tijdelijke toegangssleutels terug in de respons. Een adres als http://localhost:6379 opent net zo makkelijk de interne Redis-database, en file:///etc/passwd leest desgewenst lokale bestanden.

Veilig:

import dns from 'node:dns/promises';

const ALLOWED_HOSTS = new Set(['images.example.com', 'cdn.example.com']);

function isPrivate(ip) {
  return /^(10\.|127\.|169\.254\.|192\.168\.|::1|fc00:|fe80:)/.test(ip)
    || /^172\.(1[6-9]|2\d|3[01])\./.test(ip);
}

app.get('/fetch', async (req, res) => {
  let target;
  try { target = new URL(req.query.url); }
  catch { return res.status(400).send('Ongeldige URL'); }

  if (target.protocol !== 'https:') return res.status(400).send('Alleen https');
  if (!ALLOWED_HOSTS.has(target.hostname)) return res.status(403).send('Host niet toegestaan');

  const { address } = await dns.lookup(target.hostname);
  if (isPrivate(address)) return res.status(403).send('Geblokkeerd');

  const response = await fetch(target, { redirect: 'error' });
  res.send(await response.text());
});

De veilige variant knijpt drie kranen tegelijk dicht. Eerst wordt de invoer als echte URL geparset en beperkt tot https. Daarna moet de hostnaam voorkomen op een expliciete allowlist: alleen wat u vooraf goedkeurt, mag erdoor. Ten slotte wordt de hostnaam omgezet naar een IP-adres en gecontroleerd tegen private en link-local reeksen, zodat een goedgekeurde naam die stiekem naar 127.0.0.1 of 169.254.169.254 wijst alsnog sneuvelt. Door redirects te verbieden voorkomt u dat een externe server u in tweede instantie tóch naar binnen stuurt.

Een blocklist van “verboden” adressen is bijna altijd te omzeilen: denk aan alternatieve IP-notaties, IPv6, of een domein dat pas ná uw controle van DNS-waarde verandert (DNS rebinding). Werk daarom met een allowlist en valideer het IP-adres waarmee u daadwerkelijk verbindt.

Wat is de impact van SSRF?

De ernst van SSRF loopt sterk uiteen, en dat verklaart de spanwijdte van medium tot kritiek. In een afgeschermde omgeving zonder interessante interne diensten blijft het misschien bij het aftasten van poorten. Maar in een typische cloudopstelling is de buit groot: het metadata-endpoint (169.254.169.254) geeft tijdelijke inloggegevens vrij, en met die sleutels kan een aanvaller vaak de hele cloudomgeving overnemen.

Wat dat endpoint zo lucratief maakt, is het ontwerp. In de eerste versie, IMDSv1, volstaat een gewoon GET-verzoek: geen header, geen authenticatie, precies het ene dat SSRF een aanvaller laat doen. IMDSv2 vraagt eerst een PUT-verzoek voor een kortlevend token dat elke volgende vraag in een header moet meesturen; ook Azure en Google Cloud eisen een extra header. AWS bouwt IMDSv1 af: sinds 2024 kunt u per account instellen dat elke nieuwe instance IMDSv2 vereist, en instancetypes die sinds medio 2024 zijn verschenen accepteren af fabriek alleen nog IMDSv2, maar bestaande instances en starts vanaf oudere images beantwoorden dat simpele GET-verzoek vaak nog steeds. Hoeveel een gestolen sleutel waard is, bepaalt de rol van de instance: mag die objectopslag lezen of secrets ophalen, dan mag de aanvaller dat ook. En omdat zulke inloggegevens meestal uren geldig blijven, worden ze één keer buitgemaakt en daarna hergebruikt vanaf de eigen infrastructuur van de aanvaller, buiten het zicht van uw netwerkmonitoring.

Technisch gezien opent SSRF de deur naar alles wat de server intern kan bereiken: adminpanelen zonder externe toegang, interne API’s, databases, de Kubernetes-API of een berichtenwachtrij. De aanvaller kan het interne netwerk in kaart brengen, gevoelige data buitmaken en soms een SSRF ombuigen tot volledige remote code execution. Voor het bedrijf betekent dat datalekken, misbruik van clouddiensten op uw rekening en een aanvaller die zich vanuit één zwak endpoint lateraal door de infrastructuur beweegt. Een bekend voorbeeld is het datalek bij Capital One in 2019, waarbij een SSRF-aanval de AWS-metadata bereikte en gegevens van ruim honderd miljoen klanten blootlegde.

Hoe spoor je SSRF op?

Bij een handmatige test voert een pentester in elk veld dat een URL of host lijkt te accepteren een adres in dat naar een server onder eigen beheer wijst, en let vervolgens op de callback. Komt er een DNS- of HTTP-verzoek binnen, dan haalt de applicatie het adres dus daadwerkelijk op. Ook zonder zichtbare respons, de zogeheten blinde SSRF, verraadt zo’n uitgaand verzoek de kwetsbaarheid. Daarnaast worden metadata-endpoints, alternatieve IP-notaties en redirects beproefd om filters te omzeilen.

Om callbacks herleidbaar te houden, geeft een tester elk geteste veld een eigen subdomein; een lookup voor field7.test.example.net laat dan meteen zien welke invoer die veroorzaakte. Het maakt ook uit of alleen een DNS-query binnenkomt of dat er een volledige HTTP-verbinding volgt, want een kale naamresolutie kan ook van een proxy of een beveiligingsapparaat komen. Verschijnt er helemaal geen callback, dan nemen zijkanalen het over: een gesloten interne poort wordt direct geweigerd, een gefilterde loopt tegen de time-out aan, een open poort antwoordt snel. Die tijden en afwijkende statuscodes brengen het interne netwerk in kaart, ook al geeft de applicatie zelf niets prijs.

Waar u zoekt, telt net zo zwaar als hoe, want niet elke kwetsbare invoer heet url. Doeladressen verstoppen zich in webhookconfiguratie, in XML-documenten met een externe entity, in geüploade SVG-bestanden die een converter aan de serverkant rendert, en in headers als Referer. Het ophalen gebeurt vaak pas later in een achtergrondtaak, dus een listener die te vroeg wordt uitgezet, mist juist die gevallen.

Geautomatiseerde scanners markeren verdachte URL-parameters, maar missen vaak juist de blinde varianten. AssistSec neemt SSRF standaard mee in een penetratietest en controleert nadrukkelijk die blinde gevallen.

Hoe voorkom je SSRF?

Eén maatregel is zelden genoeg. Wat werkt, is een keten: strikte validatie in de applicatie, een krap ingericht netwerk en een cloudconfiguratie die zo weinig mogelijk weggeeft.

  • Accepteer waar het kan helemaal geen vrije URL. Laat de gebruiker kiezen uit vooraf geregistreerde bestemmingen en geef alleen hun identifier door.
  • Werk met een allowlist van toegestane hosts, domeinen en protocollen; weiger al het andere. Valideer de geparste URL in plaats van de ruwe tekst, en weiger ingebedde inloggegevens en ongebruikelijke poorten.
  • Sta alleen http en https toe en blokkeer schema’s als file, gopher, ftp en dict.
  • Zet de hostnaam om naar een IP-adres en blokkeer private, loopback en link-local reeksen, inclusief IPv6 en 169.254.169.254.
  • Maak daarna verbinding met precies dat gevalideerde IP-adres en geef de oorspronkelijke hostnaam alleen mee in de Host-header en SNI; zo sluit u het venster waar DNS rebinding op leunt.
  • Verbied redirects of valideer elke redirect opnieuw tegen dezelfde regels, met een maximum aantal stappen, en behandel elke stap als nieuwe, onbetrouwbare invoer.
  • Leid uitgaand verkeer via een forward proxy die de allowlist centraal afdwingt, zodat niet elke nieuwe functie de regels opnieuw hoeft te bouwen.
  • Draai de fetch-functionaliteit met minimale rechten in een apart, afgeschermd netwerksegment.
  • Schakel cloud-metadata uit of dwing IMDSv2 af met een token en een hop limit van 1, zodat één simpel GET-verzoek geen sleutels prijsgeeft, en geef elke workload een eigen rol met minimale rechten.
  • Geef de opgehaalde inhoud niet ongefilterd terug: begrens de omvang en het geaccepteerde contenttype, en antwoord bij elke fout op dezelfde manier, zodat statuscode noch responstijd iets over het interne netwerk verraadt.
  • Monitor uw uitgaande verkeer op onverwachte bestemmingen en alarmeer bij verbindingspogingen naar loopback-, link-local- en private reeksen.

Bronnen

Veelgestelde vragen

Wat is het verschil tussen SSRF en CSRF?

Bij CSRF misbruikt een aanvaller de browser van een ingelogde gebruiker om ongewenste acties uit te voeren. Bij SSRF misbruikt hij de server zelf om verbindingen te maken naar interne adressen. CSRF speelt zich af aan de clientkant, SSRF aan de serverkant.

Is blinde SSRF gevaarlijk als ik geen respons terugkrijg?

Ja. Ook zonder zichtbare respons kan een aanvaller interne poorten aftasten, diensten aanroepen die alleen op een verzoek reageren, of de kwetsbaarheid als opstap naar andere aanvallen gebruiken. Uitgaande DNS- of HTTP-verzoeken verraden de zwakte.

Beschermt een firewall tegen SSRF?

Niet vanzelf. De server maakt de verbinding vanuit het interne netwerk, dus vaak juist vanachter de firewall. Segmentatie helpt de schade te beperken, maar de invoervalidatie in de applicatie blijft de echte verdediging.

Waarom is een blocklist niet genoeg tegen SSRF?

Blocklists zijn bijna altijd te omzeilen met alternatieve IP-notaties, IPv6-adressen, redirects of DNS die pas na uw controle van waarde verandert (DNS rebinding). Een allowlist plus IP-validatie is betrouwbaarder.

Verwante artikelen

Druk op / om te zoeken · Esc