Arribem a l'última categoria del Top Ten i a la segona de les novetats de 2021 (juntament amb A04 Disseny Insegur). A10:2021 – Server-Side Request Forgery (SSRF) va entrar a la llista impulsada per l'enquesta a la comunitat i per la seva creixent rellevància en entorns cloud. La idea és tan simple com perillosa: si una funcionalitat fa que el servidor faci una petició HTTP (o una altra) a una URL que l'usuari controla, un atacant pot aconseguir que el servidor demani coses que ell no podria demanar directament: serveis interns, panells d'administració, i —el més cobejat al núvol— el servei de metadades que exposa credencials de la instància.
Ja vam fregar l'SSRF a la lliçó d'XXE (03-07), on una entitat externa feia que el parser XML anés a buscar una URL. Aquí el tractem de manera general i amb el seu exemple canònic a BazarNube: una funció que descarrega una imatge des d'una URL proporcionada per l'usuari (per exemple, per importar la foto de perfil o la imatge d'un producte des d'un enllaç). Ben feta és còmoda; mal feta, és una porta a la xarxa interna.
Avís legal i ètic: els exemples d'accés a serveis interns i metadades són il·lustratius i amb dades fictícies. Practica només sobre sistemes propis o amb autorització explícita. Arribar a la xarxa interna o als metadades d'un sistema aliè sense permís és delicte.
Contingut
- Què és l'SSRF i per què és tan perillós al núvol
- El cas de la descàrrega d'imatges de BazarNube
- Com s'explota (il·lustratiu)
- Prevenció 1: allowlist de destinacions
- Prevenció 2: bloquejar redireccions i adreces internes
- Prevenció 3: segmentació de xarxa i defensa en profunditat
- Errors comuns, exercicis i solucions
- Què és l'SSRF i per què és tan perillós al núvol
En un SSRF, l'atacant no ataca directament el servei intern; fa servir el servidor com a intermediari. El servidor sol estar en una posició de xarxa privilegiada: pot arribar a bases de dades, cues, panells d'administració i l'endpoint de metadades del proveïdor cloud, tots ells normalment inaccessibles des d'internet. En controlar la URL de destinació, l'atacant "manlleva" aquella posició.
L'objectiu estrella al núvol és el servei de metadades (una IP d'enllaç local, del tipus 169.254.169.254), que pot retornar credencials temporals de la instància. Amb elles, un SSRF pot escalar fins a un compromís complet del compte cloud. Per això A10 va saltar al Top Ten.
- El cas de la descàrrega d'imatges de BazarNube
El Marc va implementar una funció per importar la imatge d'un producte des d'una URL que introdueix el venedor:
// media.js — VULNERABLE a SSRF
router.post('/api/products/:id/image-from-url', requireLogin, async (req, res) => {
const { imageUrl } = req.body; // URL controlada per l'usuari
const response = await fetch(imageUrl); // el SERVIDOR fa la peticio
const buffer = Buffer.from(await response.arrayBuffer());
await saveProductImage(req.params.id, buffer);
res.json({ ok: true });
});El servidor pren imageUrl tal qual i fa fetch cap a on digui l'usuari. No es valida la destinació, ni l'esquema, ni si la URL apunta a la xarxa interna. És SSRF de manual.
- Com s'explota (il·lustratiu)
En lloc d'una imatge, l'atacant envia URLs internes:
POST /api/products/42/image-from-url
{ "imageUrl": "http://169.254.169.254/latest/meta-data/iam/security-credentials/" }El servidor, amb el seu accés privilegiat, consulta el servei de metadades i (segons la configuració) obté credencials de la instància, que poden acabar guardades o reflectides. Altres variants:
http://10.0.0.5:5432/ -> temptejar la base de dades interna http://localhost:9200/ -> un servei intern (p. ex. un cercador) sense auth file:///etc/passwd -> llegir fitxers locals (si el client segueix file://) http://intern/admin -> panell d'administracio no exposat a internet
flowchart LR A[Atacant] -->|imageUrl interna| B[API BazarNube] B -->|el servidor la sollicita| C[Metadades cloud / servei intern] C -->|resposta amb dades sensibles| B B -->|reflectida o emmagatzemada| A
- Prevenció 1: allowlist de destinacions
La defensa més robusta és una llista blanca: defineix exactament a quines destinacions pot anar la funció i rebutja tota la resta. Una llista negra ("bloqueja 169.254.169.254") és insuficient, perquè hi ha incomptables maneres d'ofuscar adreces (decimal, hexadecimal, DNS que resol a IP interna, IPv6...).
// media.js — SEGUR (part 1): allowlist d'esquema i de host
const ALLOWED_HOSTS = new Set(['cdn.proveidor-imatges.com', 'images.bazarnube.com']);
function assertAllowedUrl(raw) {
const url = new URL(raw); // llanca si no es URL valida
if (!['https:'].includes(url.protocol)) // nomes HTTPS
throw new Error('Esquema no permes');
if (!ALLOWED_HOSTS.has(url.hostname)) // nomes hosts de l'allowlist
throw new Error('Host no permes');
return url;
}Si el cas d'ús ho permet (sovint sí), el millor és no acceptar URLs arbitràries en absolut: que l'usuari pugi el fitxer directament, o que triï d'un catàleg de proveïdors permesos. Eliminar la funcionalitat de "descàrrega des d'URL lliure" elimina la classe de vulnerabilitat.
- Prevenció 2: bloquejar redireccions i adreces internes
Una allowlist de host es pot burlar de dues maneres que cal tancar:
- DNS rebinding / host que resol a IP interna: l'atacant controla un domini (
cdn.malo.example) que resol a169.254.169.254. Per això cal validar també la IP resolta, no només el nom. - Redireccions: un host permès respon amb un
302cap a una URL interna. Per això cal deshabilitar el seguiment automàtic de redireccions (o revalidar cada salt).
// media.js — SEGUR (part 2): resoldre IP, rebutjar rangs interns, sense redireccions
const dns = require('dns').promises;
const ipaddr = require('ipaddr.js');
async function assertPublicIp(hostname) {
const { address } = await dns.lookup(hostname); // IP real a la qual resol
const addr = ipaddr.parse(address);
const range = addr.range(); // 'private', 'loopback', 'linkLocal'...
if (['private', 'loopback', 'linkLocal', 'uniqueLocal', 'reserved'].includes(range))
throw new Error('Destinacio interna no permesa'); // bloqueja 10.x, 127.x, 169.254.x...
}
router.post('/api/products/:id/image-from-url', requireLogin, async (req, res) => {
try {
const url = assertAllowedUrl(req.body.imageUrl);
await assertPublicIp(url.hostname); // valida la IP resolta
const response = await fetch(url, { redirect: 'error', signal: timeout(5000) }); // sense redireccions, amb timeout
if (!response.ok) return res.status(400).json({ error: 'Descarrega fallida' });
const type = response.headers.get('content-type') || '';
if (!type.startsWith('image/')) return res.status(400).json({ error: 'No es una imatge' });
const buffer = Buffer.from(await response.arrayBuffer());
await saveProductImage(req.params.id, buffer);
res.json({ ok: true });
} catch (e) {
logger.warn({ event: 'ssrf_blocked', reqId: req.id, reason: e.message }); // enllaca amb A09
res.status(400).json({ error: 'URL no permesa' });
}
});Detalls clau: redirect: 'error' impedeix que un host permès redirigeixi cap a un d'intern; assertPublicIp rebutja qualsevol IP de rang intern (inclosa la link-local de metadades 169.254.x); el timeout limita l'abús; validar el content-type com a imatge afegeix una barrera; i l'esdeveniment bloquejat es registra (A09).
Nota sobre la cursa TOCTOU: entre resoldre la IP i fer el
fetch, el DNS podria canviar. En escenaris d'alt risc, resol la IP i connecta't a aquesta IP validada (fixant el host), o fes servir un proxy de sortida que apliqui la política de manera centralitzada.
- Prevenció 3: segmentació de xarxa i defensa en profunditat
Encara que el codi sigui perfecte, convé que la infraestructura limiti el dany:
| Capa | Control |
|---|---|
| Aplicació | Allowlist de host/esquema, validar IP resolta, sense redireccions, timeouts |
| Xarxa | Segmentar: el servei no hauria de poder arribar a la xarxa interna ni als metadades |
| Cloud | Fer servir la versió endurida del servei de metadades (que exigeix token) i rols de mínim privilegi |
| Sortida | Un proxy d'egrés que centralitzi i apliqui la política de destinacions permeses |
| Observabilitat | Registrar i alertar sobre peticions sortints anòmales (A09) |
La regla de fons, de nou, és mínim privilegi: si la funció només necessita arribar a un CDN públic, la xarxa hauria d'impedir-li físicament arribar a 169.254.169.254 o a 10.0.0.0/8. La defensa en profunditat fa que un error en una capa no sigui catastròfic.
Errors Comuns i Consells
- Acceptar URLs arbitràries de l'usuari. Si pots evitar-ho (pujada directa, catàleg), elimina la classe de vulnerabilitat.
- Fer servir llista negra d'IPs. És evadible (codificacions, DNS a IP interna). Fes servir llista blanca de hosts i valida la IP resolta.
- Seguir redireccions automàticament. Un host permès pot redirigir cap a un d'intern; fes servir
redirect: 'error'. - Validar només el nom de host, no la IP. El DNS rebinding ho burla; resol i valida el rang.
- Oblidar els metadades cloud. Són l'objectiu prioritari; bloqueja'ls per xarxa i fes servir la variant que exigeix token.
- No posar timeouts. Permeten abús i escaneig de ports per temporització.
- Consell: combina control a l'aplicació (allowlist + validació de IP), a la xarxa (segmentació) i al núvol (metadades endurits + mínim privilegi). Cap capa per si sola n'hi ha prou.
Exercicis
Exercici 1. Per què una llista negra que bloqueja 169.254.169.254 és insuficient per prevenir SSRF? Dóna dues maneres d'evadir-la.
Exercici 2. L'equip afegeix una allowlist de hosts, però continua seguint redireccions. Descriu com un atacant podria burlar l'allowlist i com es corregeix.
Exercici 3. Proposa un redisseny de la funció "imatge des d'URL" que elimini la classe de vulnerabilitat SSRF en lloc de només mitigar-la.
Solucions
Solució 1. Perquè hi ha moltes maneres de referir-se a la mateixa adreça o d'arribar a destinacions internes sense fer servir aquella cadena exacta: (a) codificacions alternatives de la IP (decimal 2852039166, hexadecimal, IPv6, 0177.0.0.1...); (b) un domini controlat per l'atacant que resol per DNS a una IP interna (rebinding). La llista negra no cobreix aquestes variants; per això es fa servir allowlist més validació de la IP realment resolta.
Solució 2. L'atacant fa servir un host permès (o un que controla i que l'allowlist accepta) que respon amb un 302 Location: http://169.254.169.254/...; si el client segueix la redirecció, acaba a la destinació interna. Es corregeix amb redirect: 'error' (o manual revalidant cada salt amb la mateixa política d'allowlist + IP).
Solució 3. Substituir la "descàrrega des d'URL lliure" per pujada directa del fitxer per part de l'usuari (multipart) o per selecció des d'un catàleg tancat de proveïdors/CDN permesos. Si el servidor mai fa una petició a una URL controlada per l'usuari, no hi ha SSRF a mitigar: la classe de vulnerabilitat desapareix per disseny (enllaça amb A04).
Conclusió
L'SSRF converteix el servidor en un còmplice involuntari que demana recursos per l'atacant, i al núvol pot escalar fins a credencials de la instància. Es prevé amb allowlist de destinacions, validació de la IP resolta, bloqueig de redireccions, timeouts, i —sobretot— segmentació de xarxa i metadades endurits. La millor mitigació, quan és viable, és no acceptar URLs arbitràries i redissenyar la funcionalitat.
Entrada de backlog — A10: funció d'imatge-des-d'URL assegurada amb allowlist de host/esquema, validació de IP resolta, redirect: 'error' i timeout; segmentació de xarxa per impedir l'accés a metadades i IPs internes; metadades cloud en mode endurit; esdeveniments SSRF bloquejats registrats al SIEM.
Tancament del mòdul 3. Hem recorregut les deu categories de l'OWASP Top Ten 2021 —A01 a A10— més les dues profunditzacions heretades (XSS i XXE), i en cadascuna hem seguit el mateix cicle sobre BazarNube: codi vulnerable → atac il·lustratiu → codi corregit → entrada al backlog. El Top Ten ens ha donat un mapa excel·lent dels riscos més freqüents, però és precisament això: els "deu més freqüents", no una checklist exhaustiva ni verificable requisit a requisit.
Per passar de "conec els grans riscos" a "puc verificar de manera sistemàtica i per nivells que la meva aplicació compleix un catàleg complet de requisits de seguretat", necessitem un estàndard més detallat i comprovable. Aquest és el salt natural del mòdul 4: OWASP ASVS (Application Security Verification Standard) en profunditat, on convertirem les lliçons d'aquest mòdul en requisits verificables organitzats per nivells d'assegurament. Moltes de les correccions que vam anotar al backlog de BazarNube reapareixeran allà com a requisits concrets de l'ASVS que sabrem verificar.
Curs d'OWASP: Directrius i Estàndards per a la Seguretat en Aplicacions Web
Mòdul 1: Introducció a OWASP
Mòdul 2: Principals Projectes d'OWASP
- OWASP Top Ten
- OWASP ASVS (Application Security Verification Standard)
- OWASP SAMM (Software Assurance Maturity Model)
- OWASP ZAP (Zed Attack Proxy)
- Altres Projectes Clau: WSTG, Cheat Sheets i Dependency-Check
Mòdul 3: OWASP Top Ten 2021 en Profunditat
- A01:2021 – Pèrdua de Control d'Accés
- A02:2021 – Errors Criptogràfics i Exposició de Dades Sensibles
- A03:2021 – Injecció
- Cross-Site Scripting (XSS) en Profunditat
- A04:2021 – Disseny Insegur
- A05:2021 – Configuració de Seguretat Incorrecta
- Entitats Externes XML (XXE)
- A06:2021 – Components Vulnerables i Desactualitzats
- A07:2021 – Errors d'Identificació i Autenticació
- A08:2021 – Errors d'Integritat de Programari i Dades (Deserialització Insegura)
- A09:2021 – Errors de Registre i Monitorització
- A10:2021 – Server-Side Request Forgery (SSRF)
Mòdul 4: OWASP ASVS (Application Security Verification Standard)
Mòdul 5: OWASP SAMM (Software Assurance Maturity Model)
Mòdul 6: OWASP ZAP (Zed Attack Proxy)
- Introducció a ZAP
- Instal·lació i Configuració
- Escaneig de Vulnerabilitats
- Automatització de Proves de Seguretat
Mòdul 7: Bones Pràctiques i Recomanacions
- Cicle de Vida de Desenvolupament Segur (SDLC)
- Modelatge d'Amenaces (Threat Modeling)
- Integració de Seguretat en DevOps (DevSecOps)
- Formació i Conscienciació en Seguretat
- Eines i Recursos Addicionals
Mòdul 8: Exercicis Pràctics i Casos d'Estudi
- Exercici 1: Identificació de Vulnerabilitats
- Exercici 2: Implementació de Controls de Seguretat
- Cas d'Estudi 1: Anàlisi d'un Incident de Seguretat
- Cas d'Estudi 2: Millora de la Seguretat en una Aplicació Web
