Respuesta rápida
CSRF (Cross-Site Request Forgery) fuerza al usuario a ejecutar acciones no deseadas en una app donde está autenticado. Ataca state-changing requests (cambiar email, transferir dinero) montadas desde otro dominio. Se mitiga con tokens CSRF validados en servidor, SameSite cookie, validación de Origin/Referer y rechazo de Content-Types inesperados. Se rompe cuando el desarrollador valida mal cualquiera de esas defensas.
Cómo funciona el ataque
CSRF aprovecha que el navegador adjunta automáticamente cookies a requests cross-site. Si la víctima está logueada en bank.tld y visita attacker.tld, una página del atacante puede hacer que el navegador envíe un POST a bank.tld/transfer con la cookie de sesión incluida.
Si el servidor solo valida la cookie, la transferencia se ejecuta como si la víctima la hubiera iniciado. Eso es CSRF.
Defensas comunes (y cómo se rompen)
1. CSRF Tokens
El servidor inyecta un token aleatorio en cada formulario. El cliente lo manda en cada request. Si no coincide → 403.
Bypasses típicos:
- Token ausente. Eliminar el parámetro del request → ¿el servidor sigue aceptando? Algunos backends solo validan si está presente.
- Token vacío.
csrf_token=(string vacío) → algunos validadores lo aceptan. - Token débil. ¿Es un valor fijo por cuenta? ¿Se reutiliza? Captura el tuyo, monta la PoC para la víctima con tu token.
- Sólo parte del token validado. Si solo se valida la mitad o un prefix, manda un token cualquiera con ese prefix válido.
- Token expira pero no se invalida. Si reutilizar tokens viejos pasa → CSRF.
2. SameSite Cookie
Atributo de cookie que controla cuándo se envía cross-site:
SameSite=Strict— nunca cross-site. Mata CSRF de raíz.SameSite=Lax(default actual en Chrome/Firefox) — solo en navegación top-level (click en link). NO en POST cross-site → bloquea CSRF clásico.SameSite=None; Secure— siempre se envía. Vulnerable.
Bypasses:
- Si la app usa
SameSite=Lax, los GET requests sí cruzan. Si una acción crítica acepta GET (/password_change?new=...), CSRF posible. - Apps legacy con cookies sin
SameSitedeclarado se comportan comoNoneen algunos navegadores.
3. Origin / Referer Header
El servidor compara el header Origin (o Referer) con su propio dominio.
Bypasses:
- Eliminar Referer.
<meta name="referrer" content="no-referrer">en la página atacante. Si el servidor "deja pasar" cuando no hay Referer → bypass. - Spoofing parcial.
Referer: example.tld.attacker.tld(subdominio que contiene el dominio target como prefix). Si el chequeo esstartsWith()ocontains(), pasa. - Origin null. Sandbox iframes envían
Origin: null→ si el servidor lo acepta, bypass.
4. Content-Type validation (para JSON APIs)
Si el endpoint exige Content-Type: application/json, no es trivial montarlo en un form HTML clásico. Pero:
- Form con
enctype="text/plain"puede generar JSON-shaped bodies:
<form action="https://target.tld/api/email" method="POST" enctype="text/plain">
<input name='{"email":"atk@evil.tld","x":"' value='"}'>
</form>
El body resultante: {"email":"atk@evil.tld","x":"="} — JSON válido si el servidor lo parsea.
- Cambiar Content-Type. Si la API también acepta
application/x-www-form-urlencodedademás de JSON → simple form CSRF. - Plain/text. Algunos backends ignoran Content-Type y parsean el body directamente.
Bypass en JSON requests
Ejemplo real:
<html>
<head><meta name="referrer" content="unsafe-url"></head>
<body>
<form name="hacker" method="POST" action="https://target.tld/api/phone.json" enctype="text/plain">
<input type="hidden" name='{"phone":"+34666000000","a":"' value='"}'>
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>
Body enviado: {"phone":"+34666000000","a":"="}. Si el server parsea como JSON, ataque exitoso.
CSRF + ClickJacking
Si el server bloquea CSRF pero la página se puede embeber en <iframe>, se monta un clickjacking:
<iframe src="https://target.tld/settings/password" width="500" height="500"></iframe>
Posicionando el iframe sobre un botón visible del attacker, el click llega al iframe target. El navegador adjunta cookies + el server procesa la acción.
Mitigación: X-Frame-Options: DENY o CSP frame-ancestors 'none'.
Endpoints donde buscar CSRF
- Cambio de email (lleva a ATO si el usuario no re-confirma).
- Cambio de contraseña.
- Cambio de 2FA settings (deshabilitar el 2FA → ATO).
- Adición de SSH keys / API keys del perfil.
- Transferencias / pagos / suscripciones.
- Eliminación de cuenta (defacement vector).
- Vinculación de cuentas OAuth/SSO (puede llevar a takeover si la víctima vincula la cuenta del atacante).
- Cambios de rol / permisos en apps con admin panel.
Patrón: CSRF relay endpoints
Algunas apps tienen endpoints internos tipo /api/proxy?url=/api/endpoint que reenvían internamente y inyectan automáticamente el CSRF token del usuario. Para el atacante, basta con que la víctima visite la URL — no necesita robar el token.
Buscar endpoints con nombres proxy, redirect, forward, relay, dialog, _DONOTUSE, _DEBUG, _INTERNAL. Si reenvían requests autenticados → posible CSRF universal.
Checklist de hunting
- ¿El servidor acepta el request sin token CSRF?
- ¿El token vacío pasa? ¿El token de otra cuenta pasa?
- ¿Hay endpoints sensibles que aceptan GET? (revisa methodOverride también).
- ¿
SameSiteestá declarado? ¿EsLax/None? - ¿Origin/Referer se valida estrictamente o solo "contains"?
- ¿Content-Type es validado o se ignora?
- ¿Existe relay/proxy endpoint que inyecte token automáticamente?
- ¿
X-Frame-Optionsestá, para descartar clickjacking?
Labs relacionados
Practica CSRF + bypasses con apps reales que validan tokens, Origin y Content-Type: labs de CSRF.
Practica esto en un lab
Csrf
Sigue aprendiendo · cuenta gratis
Guarda tu progreso, desbloquea payloads avanzados y rankea tus flags.
Artículos relacionados
Cookie flags — Secure, HttpOnly, SameSite y por qué importan
HttpOnly bloquea XSS-to-cookie, Secure obliga HTTPS, SameSite mata CSRF. Cómo se rompen y qué reportar cuando faltan en cookies sensibles.
JWT — vulnerabilidades, bypasses y manipulación de claims
alg=none, RS256→HS256 confusion, kid SQLi/path traversal, jku spoofing, secret cracking con hashcat. Cómo cazar JWTs mal verificados.
OAuth attacks — state CSRF, redirect_uri bypass, code/token leakage
El state parameter ausente, redirect_uri mal validado, response_type confusion. Cómo robar OAuth tokens y forzar account linking.