CSRF (Cross-Site Request Forgery)
Fuerza al navegador de una víctima autenticada a enviar una petición no deseada a una aplicación donde tiene sesión. El atacante no ve la respuesta; abusa de que el navegador adjunta automáticamente las credenciales (cookies) a toda petición dirigida a ese sitio, venga del origen que venga. Si una acción con efectos puede reproducirse conociendo solo su estructura y la app se fía solo de la cookie, es vulnerable. En esencia, CSRF es un fallo de verificación de intención: la app no comprueba que la petición la quiso hacer el usuario.
sequenceDiagram
participant U as Víctima (sesión activa)
participant M as Sitio del atacante
participant S as Aplicación objetivo
U->>M: visita la página maliciosa
M-->>U: formulario con autoenvío a S
U->>S: petición con las cookies de sesión
S-->>U: acción ejecutada como la víctima
Modelo de amenaza
Sección titulada «Modelo de amenaza»El impacto es el de la acción que se fuerza con la sesión de la víctima:
- Cambiar email o contraseña → el atacante toma la cuenta (ATO) sin conocer la contraseña actual.
- Transferencias, compras, cambios de plan.
- Crear usuarios o claves API, cambiar permisos.
- Modificar reglas persistentes: reenvío de correo, webhooks, DNS del router, recuperación de cuenta.
- Login CSRF: forzar a la víctima a autenticarse con la cuenta del atacante para capturar su actividad (búsquedas, tarjetas guardadas).
Anatomía
Sección titulada «Anatomía»Tres condiciones necesarias:
- Acción relevante que al atacante le interese provocar.
- Gestión de sesión basada en cookies que el navegador envía sola (no tokens en cabecera que haya que añadir por JS).
- Parámetros predecibles: sin secretos que el atacante no pueda adivinar.
Por diseño, el navegador adjunta las cookies del destino en cualquier petición
cross-site. El atributo SameSite modula ese comportamiento:
None: se envían siempre (requiereSecure).Lax(por defecto en navegadores modernos): se envían en navegaciones top-level GET (clic en un enlace), pero no en POST cross-site ni en subrecursos.Strict: no se envían en ninguna petición cross-site.
Además, las peticiones JSON con Content-Type: application/json disparan un
preflight CORS, lo que bloquea el CSRF clásico… salvo que el endpoint acepte
Content-Type “simples” (text/plain, application/x-www-form-urlencoded).
Variantes
Sección titulada «Variantes»- GET con efectos: basta una etiqueta que cargue la URL (
<img>,<link>). - POST: formulario que se autoenvía.
- JSON/APIs: explotable si el servidor acepta
text/plain/form o no valida el tipo (evita el preflight). - Multipart (
enctype=multipart/form-data): para endpoints que esperan ficheros. - Login CSRF: autenticar a la víctima con credenciales del atacante.
- CSRF → XSS: cuando la acción forzada introduce un payload almacenado.
- CSRF asistido por CORS/clickjacking: leer el token (CORS laxo) o completar un flujo (clickjacking) cuando falta un parámetro.
Red Team
Sección titulada «Red Team»Descubrimiento
Sección titulada «Descubrimiento»- Captura cada acción que cambia estado y comprueba si lleva token anti-CSRF (campo oculto, cabecera, cookie espejo).
- Si lo lleva, prueba sistemáticamente a:
- Quitarlo por completo.
- Dejarlo vacío.
- Usar un token de otra sesión / otra cuenta (¿está ligado a la sesión?).
- Usar un token válido pero caducado, o uno con la estructura correcta.
- Cambiar
POST→GET(muchos frameworks aceptan ambos). - Cambiar el
Content-Type(JSON →text/plain) para esquivar preflight.
- Revisa el
SameSitede la cookie de sesión y si la app validaOrigin/Referer.
A mano: construir el PoC
Sección titulada «A mano: construir el PoC»<!-- 1) POST autoenviado --><form action="https://banco.tld/email/change" method="POST" id="x"> <input type="hidden" name="email" value="atacante@evil.tld"></form><script>document.getElementById('x').submit()</script>
<!-- 2) GET con efectos --><img src="https://banco.tld/transfer?to=atacante&amount=1000">
<!-- 3) API JSON sin preflight (text/plain) --><form action="https://api.tld/v1/role" method="POST" enctype="text/plain"> <input name='{"role":"admin","x":"' value='"}'></form><script>document.forms[0].submit()</script>
<!-- 4) fetch cross-site (modo no-cors, para endpoints simples) --><script>fetch('https://banco.tld/email/change',{method:'POST',mode:'no-cors', credentials:'include',headers:{'Content-Type':'application/x-www-form-urlencoded'}, body:'email=atacante@evil.tld'});</script>Aloja el PoC en tu dominio y consigue que la víctima lo abra (enlace, iframe, publicidad).
Bypasses avanzados (explicados)
Sección titulada «Bypasses avanzados (explicados)»SameSite=Laxpor defecto: no cubre navegaciones top-level GET. Si una acción con efectos aceptaGET, sigue siendo explotable con un simple enlace. Tampoco cubre bien dos minutos tras emitir la cookie (ventana histórica en algunos navegadores) ni el salto entre subdominios/sitios hermanos.- Method override: APIs que aceptan
_method=POSToX-HTTP-Method-Overridepermiten mandar comoGET/formulario algo que debía ser POST. - Token no ligado a sesión: si el token es válido entre cuentas, róbalo de tu propia sesión y reúsalo en la de la víctima.
- Token predecible / estático: si no es aleatorio por sesión, se adivina.
- Double-submit débil: si la validación compara cookie vs parámetro y puedes fijar la cookie (vía un subdominio que controles o una inyección), eludes la comprobación.
- CORS mal configurado: si la app refleja el
OriginconAllow-Credentials: true, lee el token anti-CSRF con unfetchautenticado y envíalo tú. - Validación de
Referersaltable: cuando solo valida “si hay Referer”, omítelo conReferrer-Policy: no-referrer(meta) o un contextodata:.
Herramientas
Sección titulada «Herramientas»Burp Suite (Engagement tools → Generate CSRF PoC), extensiones de generación de PoC,
y curl para validar la ausencia/omisión de token.
Impacto y encadenamiento
Sección titulada «Impacto y encadenamiento»Toma de cuenta directa (cambio de email/clave), acciones privilegiadas, persistencia vía reglas (reenvío, webhooks), y CSRF→XSS→compromiso mayor. Un login CSRF puede capturar datos sensibles que la víctima introduce creyendo estar en su cuenta.
Blue Team
Sección titulada «Blue Team»Detección
Sección titulada «Detección»- Peticiones que cambian estado con
Origin/Refererausente o externo. - Patrones de token ausente/ inválido/ reutilizado en endpoints sensibles.
- Referers cross-site anómalos hacia acciones críticas; picos coordinados desde una misma campaña (mismo enlace malicioso).
- Cambios de email/clave seguidos de actividad desde una IP nueva.
Telemetría y fuentes
Sección titulada «Telemetría y fuentes»Logs con Origin/Referer/Content-Type por petición, WAF, y métricas de acciones
sensibles por usuario/origen.
Hardening
Sección titulada «Hardening»- Token anti-CSRF (synchronizer token): valor impredecible, ligado a la sesión, obligatorio y validado en servidor en toda acción que cambie estado. Alternativa: double-submit bien implementado (token en cookie + cabecera, comparados), robusto solo si el atacante no puede fijar la cookie.
- Cookies
SameSite:Laxpor defecto mitiga, pero para acciones críticas usaStricty token; no dependas solo del default. - Validar
Origin/Refereren servidor para peticiones con efectos (rechazar si no coincide con el propio origen). - APIs: exigir una cabecera personalizada (
X-Requested-With) oAuthorization: Bearer(no se adjunta sola) y rechazarContent-Typesimples en endpoints JSON (forzarapplication/jsondispara preflight). - Re-autenticación / step-up para acciones muy sensibles (cambio de email, transferencias, borrado de cuenta).
Respuesta
Sección titulada «Respuesta»Invalidar sesiones afectadas, revertir cambios forzados (email/reglas/claves), avisar
a la víctima, y añadir token/validación de Origin en el endpoint vulnerable.
CVEs y casos reales
Sección titulada «CVEs y casos reales»- ING Direct (2008) — el paper académico de Zeller & Felten demostró CSRF que permitía transferencias en la banca online; caso de estudio fundacional.
- YouTube (2008) — CSRF que permitía múltiples acciones en la cuenta de la víctima (favoritos, suscripciones, mensajes).
- Routers domésticos — oleadas de CSRF que cambiaban el DNS del router desde una web maliciosa (p. ej. campañas contra routers en Brasil y Reino Unido), redirigiendo todo el tráfico de la víctima.
- Plugins de CMS (WordPress, etc.) — CSRF (a menudo encadenado con XSS almacenado) es de los tipos de CVE más frecuentes en plugins.
CVEs concretos en NVD (https://nvd.nist.gov/vuln/search) y GitHub Advisories (https://github.com/advisories).
Checklist de prueba
Sección titulada «Checklist de prueba»- Identificadas todas las acciones que cambian estado.
- Comprobada presencia y validación del token (quitar/vaciar/otra sesión/reutilizar).
- Probada conversión
POST→GETy cambio deContent-Type(preflight). - Revisado
SameSitey validación deOrigin/Referer. - Probado method override y double-submit con cookie fijada.
- CORS evaluado como vía para robar el token.
- PoC funcional para al menos una acción de impacto (idealmente ATO).