flawopen.com/SSRF/SSRF con fetch() en Node.js
¿Node.js fetch() evita la SSRF?
No. El fetch() del servidor realiza solicitudes desde el servidor. Si quien llama elige el destino, puede dirigir la solicitud a sistemas accesibles para el servidor pero no para esa persona. Es como pedirle a un mensajero de confianza que entregue un paquete sin comprobar la dirección. La exposición depende de la red, identidad, política de URL y redirecciones.
providerId, hasta un origen configurado por la aplicación. Evita aceptar URLs arbitrarias.Causa raíz: el servidor confía en el destino elegido por el usuario
El fetch() de Node.js es un cliente HTTP general, no una política contra SSRF. No decide a qué redes puede conectarse la aplicación; CORS del navegador no establece ese límite en el servidor. Analizar la URL tampoco basta: un host permitido puede resolver a una dirección prohibida y una respuesta puede redirigir a otro host. Funciones que descargan avatares, webhooks, documentos o vistas previas proporcionados por usuarios pueden exponer este riesgo.
Cómo cruza la solicitud el límite de confianza
El usuario influye en una URL
Un endpoint acepta una URL completa o datos suficientes para construirla, por ejemplo, para mostrar una vista previa de imagen.
El servidor envía la solicitud
El cliente HTTP utiliza la ruta de red, DNS, proxy e identidad disponibles al proceso del servidor.
Una redirección puede cambiar el destino
Fetch sigue redirecciones por defecto. Un destino validado al inicio puede responder con Location hacia un host que la aplicación debía bloquear.
La respuesta puede exponer datos accesibles
Si la política y la red lo permiten, pueden alcanzarse servicios internos o metadatos de nube. Depende del entorno; no ocurre en toda llamada fetch.
Patrones Node.js vulnerable y más seguro
// No solicites una URL arbitraria proporcionada por quien llama.
const response = await fetch(userProvidedUrl);
// El usuario elige una clave, nunca un destino de red.
const destinations = new Map([
["status", new URL("https://status.example/")],
["docs", new URL("https://docs.example/")],
]);
const target = destinations.get(providerId);
if (!target) throw new Error("Unknown provider");
const response = await fetch(target, {
redirect: "error",
signal: AbortSignal.timeout(3000),
});
if (!response.ok) throw new Error("Upstream request failed");
Si los usuarios deben enviar URLs
Prefiere aceptar un identificador de proveedor y construir la solicitud desde un mapa fijo de destinos. Si son imprescindibles URLs públicas arbitrarias, permite solo esquemas y puertos necesarios; rechaza user-info, loopback, IP privadas, link-local y otros destinos IPv4/IPv6 prohibidos; valida todas las direcciones resueltas y asegura que la conexión use una dirección validada sin otra resolución no comprobada. Desactiva redirecciones automáticas o valida cada salto. Aplica reglas de salida de red independientes, incluidos los endpoints de metadatos como 169.254.169.254 y la dirección IPv6 habilitada. Limita tiempo, tamaño de respuesta y concurrencia; no reenvíes credenciales al host consultado.
Lista de prevención de SSRF
- ✓Siempre que puedas, sustituye URLs arbitrarias por un mapa fijo desde una clave de proveedor validada hasta un destino controlado por la aplicación.
- ✓Exige
https:y los puertos previstos; rechaza credenciales en la URL, hosts inesperados, IP literales y rangos prohibidos. - ✓Desactiva redirecciones con
redirect: "error"; si hacen falta, valida cada destino antes de conectar. - ✓Evita DNS rebinding validando todas las respuestas A/AAAA y vinculando la conexión a una IP validada, conservando la verificación del nombre. Aplica la regla a reintentos y proxies.
- ✓Usa firewall o proxy de salida para bloquear loopback, redes privadas, link-local y metadatos, también por IPv6. No dependas solo de la aplicación.
- ✓Establece límites de tiempo, bytes de respuesta y concurrencia; no reenvíes cookies, cabeceras de autorización ni credenciales de nube al destino.
- ✓En AWS, exige IMDSv2 y restringe el acceso a metadatos como defensa adicional; no sustituye la validación de URL ni el control de salida.
Preguntas frecuentes
No. Redirecciones, variantes IPv4/IPv6, DNS rebinding, proxies y carreras entre resolución y conexión pueden eludir comprobaciones simples. Prefiere una lista permitida de destinos. Si aceptas destinos arbitrarios, valida cada dirección y haz que la conexión use ese resultado; aplica la misma política en la salida de red.
No. IMDSv2 requiere un flujo con token y reduce algunas exposiciones, pero la SSRF puede alcanzar otros servicios internos o endpoints de metadatos según la configuración. Mantén los controles de destino y salida.
Fuentes primarias
- OWASP — prevención de SSRF
- Node.js — API global fetch
- Estándar WHATWG Fetch — modo de redirección
- AWS — opciones del servicio de metadatos EC2
- CWE-918 — Server-Side Request Forgery