¿Qué es una cookie?

Una cookie es un pequeño fragmento de datos que el servidor envía al navegador mediante la cabecera Set-Cookie. El navegador la almacena y la reenvía automáticamente en cada petición al mismo dominio.

Su uso más importante en seguridad: mantener sesiones de usuario. Después de hacer login, el servidor te entrega un token de sesión en una cookie; en cada petición el navegador lo envía y el servidor sabe quién eres.

Formato completo

nombre=valor

El dato en sí. Para sesiones suele ser un token opaco largo y aleatorio, nunca información sensible en claro.

Domain y Path

A qué dominio y ruta se envía la cookie. Domain=.ejemplo.com incluye subdominios.

Expires / Max-Age

Cuándo expira. Sin este atributo es una session cookie: desaparece al cerrar el navegador.

HttpOnly / Secure / SameSite

Los tres flags de seguridad. Cada uno protege contra un vector de ataque diferente.

Ver tus cookies en el navegador

DevTools → Application → Cookies
Abre las DevTools (F12), ve a la pestaña Application y selecciona Cookies en el panel izquierdo. Puedes ver todas las cookies del sitio actual, sus valores y sus flags. Para ver solo las accesibles desde JS: abre la consola y escribe document.cookie.
⚠️ Esto verás en este laboratorio
Este lab establece intencionalmente una cookie lab_session sin la flag HttpOnly. Podrás leerla con document.cookie y exfiltrarla mediante XSS. Así es como funciona el robo de sesión.

Flag HttpOnly — Contra el robo de cookies por XSS

La flag HttpOnly instruye al navegador para que no exponga la cookie a JavaScript. document.cookie simplemente no la incluirá en su resultado.

Cómo configurarla

Node.js / Express
// ❌ Vulnerable — cookie accesible desde JS
res.cookie('session', token);

// ✅ Seguro — JavaScript no puede leerla
res.cookie('session', token, {
  httpOnly: true,
  secure: true,
  sameSite: 'strict'
});
HTTP Header
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Strict
HttpOnly no protege contra todo
Aunque JavaScript no puede leer una cookie HttpOnly, el navegador sí la envía automáticamente en cada petición HTTP al servidor. Un ataque CSRF puede explotar esto: no necesita leer la cookie, solo necesita que el navegador la incluya en una petición maliciosa.

Flag Secure — Contra el robo en tránsito

La flag Secure indica al navegador que solo envíe la cookie a través de HTTPS, nunca por HTTP plano. Protege contra ataques de interceptación en la red (Man-in-the-Middle).

Secure + HSTS = protección completa en tránsito
Combinar la flag Secure con la cabecera Strict-Transport-Security (HSTS) garantiza que el navegador nunca haga peticiones HTTP al servidor, eliminando cualquier vector de degradación de protocolo (SSL stripping).
HTTP Headers
Set-Cookie: session=abc123; Secure; HttpOnly
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

Flag SameSite — Contra CSRF

La flag SameSite controla si el navegador envía la cookie en peticiones cross-site (originadas desde un dominio diferente). Es la defensa principal contra ataques CSRF.

Los tres valores

Valor Petición misma web Navegación GET cross-site POST / iframe cross-site Protege contra CSRF
None ✅ Sí ✅ Sí ✅ Sí ❌ No
Lax Default ✅ Sí ⚠️ Solo top-level GET ❌ No ⚠️ Parcial
Strict ✅ Sí ❌ No ❌ No ✅ Sí

SameSite=None

La cookie se envía en todos los contextos, incluyendo peticiones desde otros dominios. Necesario para integraciones (pagos, widgets), pero peligroso como valor por defecto. Requiere también la flag Secure.

SameSite=Lax

Comportamiento por defecto en navegadores modernos. La cookie se envía en navegación de nivel superior (clics en enlaces) pero no en peticiones POST, iframes o carga de recursos desde otros sitios.

SameSite=Strict

La cookie nunca se envía en peticiones cross-site, ni siquiera al hacer clic en un enlace desde otro sitio. Máxima protección contra CSRF, pero puede afectar la usabilidad (redirecciones post-login).

Recomendación

Para cookies de sesión: usa SameSite=Strict si tu app no necesita funcionar desde enlaces externos, o SameSite=Lax como mínimo. Combínalo con tokens anti-CSRF para defensa en profundidad.

Ejemplo visual: SameSite=None vs Strict

CSRF — Cross-Site Request Forgery

Conceptual — Sin lab ejecutable
CSRF requiere dos dominios distintos para demostrar el ataque. Aquí lo explicamos en detalle con diagramas. Todos los labs de este entorno están en el mismo dominio, lo que hace imposible simular un CSRF real directamente. Pero entender CSRF es esencial para saber por qué los flags SameSite y los tokens anti-CSRF existen.

¿Qué es CSRF?

CSRF (Cross-Site Request Forgery, o falsificación de petición entre sitios) es un ataque que fuerza al navegador de la víctima a ejecutar una petición autenticada a una aplicación web en la que está logueada, sin su conocimiento ni consentimiento.

La clave es que el navegador envía las cookies automáticamente. El atacante no necesita robar la cookie: solo necesita que el navegador de la víctima haga una petición al sitio objetivo, y el navegador la incluirá solo.

Flujo de ataque CSRF clásico

1
La víctima inicia sesión en banco.com. El servidor establece: Set-Cookie: session=TOKEN
2
La víctima, sin cerrar sesión, visita evil.com (un email, un anuncio, un enlace en foro...)
3
evil.com tiene código HTML oculto:
<form action="https://banco.com/transferir" method="POST" id="f">
  <input type="hidden" name="destino" value="atacante123">
  <input type="hidden" name="cantidad" value="5000">
</form>
<script>document.getElementById('f').submit();</script>
4
El navegador envía el POST a banco.com e incluye automáticamente la cookie session=TOKEN
5
banco.com recibe una petición autenticada válida y ejecuta la transferencia. La víctima ha sido atacada sin saberlo.

Defensas contra CSRF

1. Token anti-CSRF

El servidor genera un token aleatorio y lo incluye en cada formulario como campo oculto. En cada POST verifica que el token coincide. El atacante no puede conocer el token.

<input type="hidden"
  name="_csrf"
  value="X7k2mN9pQr...">

2. SameSite=Strict

El flag SameSite impide que el navegador incluya la cookie en peticiones cross-site. Sin cookie, la petición no está autenticada y el servidor la rechaza.

3. Verificar Origin / Referer

El servidor comprueba que la cabecera Origin o Referer de la petición coincide con el dominio esperado. Si viene de evil.com, se rechaza.

4. Double Submit Cookie

El servidor establece una cookie con un valor aleatorio y exige que ese mismo valor se envíe también como parámetro de formulario. El atacante no puede leer la cookie para duplicarla.

CSRF + XSS = combo letal

⚠️ Cuando XSS rompe todas las defensas CSRF

Si hay XSS en el mismo dominio, un atacante puede:

  • Leer el token anti-CSRF del DOM con document.querySelector('[name=_csrf]').value
  • Incluirlo en la petición forjada junto con la cookie de sesión
  • Bypassear todas las protecciones CSRF simultáneamente

Por eso se dice que XSS invalida CSRF: si hay XSS en tu dominio, los tokens anti-CSRF no sirven de nada.