Sécurité

Cookies seguras: Guía de seguridad web

Configura cookies seguras en tu aplicación web. Flags HttpOnly, Secure, SameSite, prefijos y buenas prácticas.

28 mars 20264 min de lectureWarDek Team

Las cookies son el mecanismo principal de gestión de sesiones en la web. Una cookie de sesión mal configurada es una puerta abierta: permite robo de sesión (XSS), suplantación de identidad (CSRF) y violaciones de privacidad (RGPD). La buena noticia: configurar cookies de forma segura requiere apenas unas líneas de código.

Anatomía de una cookie segura

Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=3600; Domain=tusitio.es

Cada atributo tiene una función de seguridad específica:

Los flags de seguridad

HttpOnly

Set-Cookie: session=abc123; HttpOnly

Qué hace: impide que JavaScript acceda a la cookie a través de document.cookie.

Por qué importa: si un atacante logra ejecutar un XSS en tu sitio, sin HttpOnly puede robar la cookie de sesión con document.cookie. Con HttpOnly, la cookie es inaccesible desde JavaScript — solo se envía automáticamente en las peticiones HTTP.

Cuándo usarlo: SIEMPRE en cookies de sesión y tokens de autenticación. NUNCA en cookies que JavaScript necesita leer (preferencias de tema, idioma).

Secure

Set-Cookie: session=abc123; Secure

Qué hace: la cookie solo se envía en conexiones HTTPS.

Por qué importa: sin Secure, la cookie se envía también por HTTP (sin cifrar), permitiendo su interceptación en redes no seguras (cafeterías, aeropuertos).

Cuándo usarlo: SIEMPRE en producción. En desarrollo local (localhost), los navegadores hacen una excepción.

SameSite

Set-Cookie: session=abc123; SameSite=Lax

Qué hace: controla cuándo se envía la cookie en peticiones cross-site.

| Valor | Comportamiento | Protección CSRF | |-------|---------------|-----------------| | Strict | Solo se envía en peticiones del mismo sitio | Máxima (pero puede romper flujos de navegación) | | Lax | Se envía en navegación directa (links), no en formularios/AJAX cross-site | Buena (recomendado) | | None | Se envía siempre (requiere Secure) | Ninguna (solo si es necesario) |

Recomendación: Lax para la mayoría de los casos. Strict si no necesitas que la cookie funcione al llegar desde otro sitio. None solo para cookies de terceros (que están siendo eliminadas por los navegadores).

Path

Set-Cookie: session=abc123; Path=/

Qué hace: limita la cookie a un path específico del sitio.

Recomendación: Path=/ para cookies de sesión. Paths más restrictivos para cookies específicas de secciones.

Domain

Set-Cookie: session=abc123; Domain=tusitio.es

Qué hace: define en qué dominios se envía la cookie. Si especificas Domain=tusitio.es, la cookie se envía también a subdominios (api.tusitio.es, admin.tusitio.es).

Recomendación: omitir Domain si la cookie solo debe funcionar en el dominio exacto (más restrictivo).

Max-Age / Expires

Set-Cookie: session=abc123; Max-Age=3600

Qué hace: define cuándo expira la cookie.

Recomendación: sesiones activas de 30 min a 24h máximo. Remember-me: 30 días máximo con renovación.

Prefijos de cookies

Los navegadores modernos soportan prefijos especiales:

__Secure-

Set-Cookie: __Secure-session=abc123; Secure; Path=/

El navegador rechaza esta cookie si no cumple el flag Secure. Previene que un atacante en HTTP sobrescriba la cookie.

__Host-

Set-Cookie: __Host-session=abc123; Secure; Path=/; SameSite=Lax

Más restrictivo: requiere Secure, Path=/, y NO puede tener Domain. La cookie solo funciona en el dominio exacto. Es la opción más segura para cookies de sesión.

Configuración por framework

Express.js

app.use(session({
  name: '__Host-session',
  secret: process.env.SESSION_SECRET,
  cookie: {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'lax',
    maxAge: 1800000, // 30 minutos
    path: '/',
  },
  resave: false,
  saveUninitialized: false,
}));

Next.js (Server Actions / API Routes)

import { cookies } from 'next/headers';

const cookieStore = await cookies();
cookieStore.set('session', tokenValue, {
  httpOnly: true,
  secure: process.env.NODE_ENV === 'production',
  sameSite: 'lax',
  maxAge: 1800, // 30 minutos en segundos
  path: '/',
});

PHP

session_set_cookie_params([
    'lifetime' => 1800,
    'path' => '/',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Lax',
]);
session_start();

Errores comunes

No usar HttpOnly en cookies de sesión. Es la protección más básica contra robo de sesión por XSS. No hay excusa para omitirlo.

SameSite=None sin Secure. Los navegadores rechazan cookies con SameSite=None que no tengan Secure.

Cookies de sesión sin expiración. Una cookie sin Max-Age es cookie de sesión del navegador (se borra al cerrar), pero si el usuario nunca cierra el navegador, la sesión dura para siempre.

Almacenar datos sensibles en la cookie. La cookie debe contener solo el ID de sesión, nunca datos del usuario (email, rol, permisos).

No regenerar la sesión tras login. Después de autenticar al usuario, genera un nuevo token de sesión para prevenir session fixation.

Checklist cookies seguras

Cómo WarDek verifica tus cookies

WarDek analiza automáticamente las cookies de tu sitio web:


Escanea tu sitio web gratis con WarDek — OWASP, NIS2, RGPD, AI Act en un solo escaneo.

#cookies#seguridad-web#sesiones#csrf

Scannez votre site gratuitement

WarDek détecte les vulnérabilités mentionnées dans cet article en quelques secondes.

Retour à Sécurité