¿Cómo funciona realmente el CSRF, y cómo lo detienen los tokens junto con las cookies SameSite?
El CSRF convierte en arma la confianza que el navegador deposita en una sesión iniciada — el atacante nunca ve tu cookie, simplemente logra que tu navegador la gaste.
APRENDE HACIENDOPon a prueba tu intuición3 pasos
¿Cómo funciona realmente el CSRF, y cómo lo detienen los tokens junto con las cookies SameSite?
Usa los ejemplos y la explicación de la lección para comprobar tu idea.
Reflexión personal. No se envía a ningún servicio de IA.#Por qué el CSRF funciona en primer lugar
El Cross-Site Request Forgery explota un hecho muy específico de los navegadores: cuando un navegador envía una solicitud a bank.com, adjunta automáticamente todas las cookies asociadas a bank.com — sin importar qué página u origen inició esa solicitud. Si estás logueado en tu banco en una pestaña y la página de un atacante en otra pestaña envía silenciosamente un formulario a bank.com/transfer, tu navegador adjunta felizmente tu cookie de sesión. El servidor del banco ve una solicitud perfectamente autenticada; no tiene forma de saber que el usuario nunca tuvo la intención de enviarla.
Por eso el CSRF a menudo se malentiende como "robo de cookies" — no lo es. El atacante nunca lee el valor de tu cookie. Simplemente logra que tu navegador, que ya tiene una sesión válida, dispare una solicitud en su nombre. Eso es todo el ataque.
#Anatomía de un ataque
La víctima nunca ve que algo ocurra — el formulario puede enviarse vía JavaScript al cargar la página, o el "ataque" puede ser tan simple como un <img src="https://bank.com/transfer?to=atacante&amount=5000"> si el banco fue lo bastante descuidado como para permitir que una solicitud GET modifique estado.
#Defensa 1: cookies SameSite
El atributo de cookie SameSite le indica al navegador cuándo adjuntar una cookie en una solicitud cross-site:
SameSite=Strict— nunca envía la cookie en una solicitud cross-site, ni siquiera cuando el usuario hace clic en un enlace desde otro dominio hacia el tuyo. Es hermético contra CSRF, pero rompe el caso en que un usuario sigue un enlace externo y espera ya estar logueado.SameSite=Lax(el valor por defecto en navegadores modernos cuando no se especifica) — envía la cookie en navegaciones de nivel superior por GET (hacer clic en un enlace) pero la retiene en POSTs cross-site, cargas de imágenes y de iframes. Esto por sí solo bloquea el ataque clásico de auto-envío de formulario descrito arriba, ya que el POST falsificado no llevará la cookie.SameSite=None— siempre se envía cross-site; requiereSecure. Necesario para casos de uso cross-site legítimos (un widget embebido, un iframe de pago) y no ofrece ninguna protección contra CSRF por sí sola.
SameSite=Lax cierra la mayoría de los ataques de CSRF gratis, por lo que es el valor por defecto en los navegadores actuales. Pero no es una solución completa: no cubre ataques por toma de subdominios, no ayuda con clientes que no usan cookies como credencial principal (algunos clientes móviles/de API), y los navegadores más antiguos pueden no aplicarlo en absoluto. Trátalo como una capa, no como la única capa.
#Defensa 2: el patrón de token sincronizador
La mitigación clásica, y todavía estándar, es un token CSRF: un valor impredecible, por sesión (o por solicitud), que el servidor incrusta en cada formulario que renderiza, y que exige de vuelta en cada solicitud que cambia estado. Como el token no es una cookie, la solicitud cross-site falsificada del atacante no tiene forma de conocerlo ni de adjuntarlo.
// servidor: emitiendo un token ligado a la sesiónconst crypto = require('crypto');app.get('/transfer-form', (req, res) => {const token = crypto.randomBytes(32).toString('hex');req.session.csrfToken = token; // guardado del lado del servidor, ligado a esta sesiónres.render('transfer', { csrfToken: token });});// servidor: verificando el token en la solicitud que muta estadofunction verifyCsrfToken(req, res, next) {const submitted = req.body._csrf;const expected = req.session.csrfToken;if (!submitted || !expected) {return res.status(403).send('Falta el token CSRF');}const a = Buffer.from(submitted);const b = Buffer.from(expected);// comparación en tiempo constante: un === simple filtra información de tiempo// proporcional a cuántos caracteres iniciales coinciden, lo cual un// atacante puede usar para adivinar el token byte por byteif (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {return res.status(403).send('Token CSRF inválido');}next();}app.post('/transfer', verifyCsrfToken, (req, res) => {// se confirmó que el token coincide con esta sesión — es seguro ejecutar la transferenciaperformTransfer(req.body.to, req.body.amount);res.redirect('/dashboard');});
Dos detalles de implementación separan una verificación de CSRF correcta de una rota. Primero, la comparación debe ser en tiempo constante (crypto.timingSafeEqual, no ===), porque una comparación de strings ingenua retorna más rápido cuanto antes encuentra un byte que no coincide — un atacante que mida la latencia de la respuesta a través de muchos intentos puede reconstruir el token carácter por carácter. Segundo, el token debe estar ligado a la sesión del lado del servidor (o derivado criptográficamente del id de sesión), no simplemente devuelto y aceptado de buena fe, de lo contrario un atacante que pueda plantar cualquier token mediante alguna otra vulnerabilidad que permita fijar cookies anula por completo la verificación.
#Por qué generalmente quieres ambas cosas
SameSite=Lax/Strict y los tokens CSRF defienden contra modelos de amenaza que se superponen pero no son idénticos. SameSite es un control de capa de red aplicado por el navegador que no cuesta nada implementar y cubre la mayoría de los casos por defecto. Los tokens CSRF son un control de capa de aplicación que además protege contra ataques basados en subdominios, CORS mal configurado y navegadores antiguos que ignoran SameSite. Confiar solo en SameSite es razonable para una aplicación web moderna, basada en cookies, con control estricto sobre sus subdominios; confiar solo en tokens es el valor por defecto más seguro cuando no puedes garantizar que todos los clientes apliquen SameSite correctamente. La mayoría de las aplicaciones maduras usan ambas cosas, más una verificación de mismo origen sobre el encabezado Origin/Referer como una tercera señal barata.
🧠 Check your understanding
0/2 · 0/2 answered1. ¿Por qué es posible el CSRF aunque el atacante nunca llegue a conocer el valor de la cookie de sesión de la víctima?
2. ¿Qué bloquea específicamente SameSite=Lax que SameSite=None no bloquea?