privacy

Atributos de cookies seguras

MetricSpot inspecciona las cabeceras Set-Cookie buscando Secure, HttpOnly y SameSite. Si falta alguno, se amplía la superficie de ataque a robo de cookies y CSRF.

Qué comprueba esta verificación

Lee cada cabecera de respuesta Set-Cookie y comprueba tres flags:

  • Secure — la cookie solo se envía sobre HTTPS.
  • HttpOnly — la cookie no es legible desde JavaScript (bloquea el robo vía XSS).
  • SameSite=Lax|Strict|None — comportamiento en peticiones cross-site (bloquea CSRF).

Aprueba cuando toda cookie que lleve estado de autenticación o sesión tiene los tres.

Por qué importa

Las cookies guardan las llaves de las sesiones de tus usuarios. Una cookie sin estos flags está a una vulnerabilidad XSS o a una Wi-Fi hostil de un secuestro de cuenta:

  • Sin Secure → la cookie viaja sobre HTTP plano en la primera petición antes de que entre HSTS. Esnifable en la Wi-Fi de una cafetería.
  • Sin HttpOnly → cualquier script inyectado (XSS, dependencia npm maliciosa, anuncio hostil) puede leer la cookie vía document.cookie y exfiltrarla.
  • Sin SameSite → cross-site request forgery (CSRF). Una página maliciosa puede enviar formularios o disparar peticiones como tu usuario logueado.

Los navegadores llevan años apretando los defaults: Chrome envía hoy SameSite=Lax por defecto, pero el código heredado que setea cookies sin flags explícitos sigue filtrando.

Cómo arreglarlo

Configura toda cookie de sesión/auth con los tres flags.

Set-Cookie: session=abc123; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=86400

Express / Node.js:

res.cookie("session", token, {
  httpOnly: true,
  secure: true,
  sameSite: "lax",
  maxAge: 86400 * 1000,
  path: "/",
});

Next.js (App Router con cookies()):

import { cookies } from "next/headers";

cookies().set({
  name: "session",
  value: token,
  httpOnly: true,
  secure: true,
  sameSite: "lax",
  path: "/",
  maxAge: 86400,
});

Bun.serve():

return new Response("ok", {
  headers: {
    "Set-Cookie": `session=${token}; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=86400`,
  },
});

Django:

# settings.py
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = "Lax"
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = True
CSRF_COOKIE_SAMESITE = "Lax"

Rails:

# config/initializers/session_store.rb
Rails.application.config.session_store :cookie_store,
  key: "_app_session",
  secure: Rails.env.production?,
  httponly: true,
  same_site: :lax

PHP / WordPress: en wp-config.php o antes de cualquier output:

ini_set('session.cookie_secure', '1');
ini_set('session.cookie_httponly', '1');
ini_set('session.cookie_samesite', 'Lax');

¿Qué valor de SameSite?

  • Strict — la cookie nunca se envía en peticiones cross-site. Máxima protección, pero rompe el caso en el que los usuarios siguen un enlace hacia tu sitio y aterrizan deslogueados. Bueno para flujos de alto riesgo (admin, banca).
  • Lax (por defecto) — la cookie se envía en navegaciones top-level (clicar un enlace) pero no en POSTs cross-site, iframes ni peticiones de imagen. El default correcto para la mayoría de sitios.
  • None — la cookie se envía en todas las peticiones cross-site. Requiere Secure. Úsalo solo cuando realmente necesites contexto de terceros (widgets embebidos, proveedores de identidad).

Los prefijos de nombre de cookie añaden una segunda capa de aplicación:

  • __Secure- — el navegador rechaza setear la cookie si no se pone también Secure.
  • __Host- — el navegador rechaza si no se pone Secure, Path=/ y sin atributo Domain.
Set-Cookie: __Host-session=abc123; Path=/; Secure; HttpOnly; SameSite=Lax

Combina esta regla con HTTPS, activar HSTS y la cabecera referrer-policy para una línea base completa de seguridad en el transporte.

Preguntas frecuentes

¿HttpOnly va a romper mi código cliente?

Solo si lees la cookie desde JavaScript. Para cookies de sesión/auth no deberías hacerlo — la cookie debe ser opaca al cliente y solo usada por el servidor. Si guardas datos que el JS necesita leer, eso es otra categoría de cookie (preferencias, estado de UI) y HttpOnly no aplica.

¿Y las cookies de consentimiento y analítica?

Las cookies de consentimiento y analítica a menudo necesitan genuinamente ser legibles desde JavaScript. Pónles Secure y SameSite=Lax, pero salta HttpOnly. La verificación de MetricSpot tolera esto — solo avisa cuando una cookie de sesión no tiene los flags.

¿Afecta esto al cumplimiento del GDPR directamente?

No por el lado de consentimiento/base legal, sino por el de seguridad. El artículo 32 del GDPR exige “medidas técnicas apropiadas” — la falta de flags en las cookies se cita rutinariamente en decisiones de autoridades de control como fallo de seguridad. Combínalo con un banner de consentimiento de cookies y un enlace a política de privacidad para la capa legal.

Fuentes

Última actualización 2026-05-11