Autenticación segura en aplicaciones web: lo que no puedes ignorar
La autenticación es el componente de seguridad más crítico de cualquier aplicación web. Es también el que más frecuentemente encontramos mal implementado en proyectos que llegan a nosotros para revisión o mantenimiento.
No porque los desarrolladores no sepan que importa. Sino porque los errores son sutiles y sus consecuencias no se ven hasta que alguien los explota.
Los errores más comunes que vemos en producción
1. Contraseñas almacenadas con MD5 o SHA-1
Todavía en 2025 encontramos bases de datos con contraseñas hasheadas con MD5 o SHA-256 sin sal. Estos hashes son susceptibles a ataques de diccionario y rainbow tables — con hardware moderno, una contraseña débil se puede crackear en segundos.
La solución: usa bcrypt, Argon2 o scrypt. Son algoritmos diseñados específicamente para contraseñas, con un factor de costo que puedes ajustar para que el hash sea más lento de calcular a medida que el hardware mejora.
import bcrypt from 'bcrypt';
// Almacenar
const hash = await bcrypt.hash(password, 12); // 12 rondas
// Verificar
const valid = await bcrypt.compare(inputPassword, storedHash);
2. Tokens JWT sin expiración (o con expiración muy larga)
Un JWT sin fecha de expiración es válido para siempre. Si ese token se filtra — en un log, en un error de cliente, en una extensión de browser maliciosa — el atacante tiene acceso indefinido.
La solución: expira los access tokens en minutos (15–60 min) y usa refresh tokens de larga duración almacenados en cookies HttpOnly para renovarlos. Si necesitas invalidar sesiones, mantén una lista de refresh tokens en Redis o la base de datos.
3. Cookies sin las flags correctas
Una cookie de sesión sin HttpOnly puede ser robada por JavaScript malicioso (XSS). Sin Secure se envía en HTTP sin cifrar. Sin SameSite=Strict o Lax es vulnerable a CSRF.
La solución:
Set-Cookie: session=...; HttpOnly; Secure; SameSite=Lax; Path=/
4. Rate limiting ausente en el endpoint de login
Sin rate limiting, un atacante puede intentar millones de combinaciones de contraseña por fuerza bruta. El endpoint de login es el más atacado de cualquier aplicación.
La solución: limita los intentos por IP y por usuario. Después de 5 intentos fallidos en 15 minutos, introduce un delay progresivo o bloquea temporalmente. Usa Upstash Redis o similar para el conteo distribuido.
5. Restablecimiento de contraseña con tokens predecibles
Un token de reset que es solo el timestamp del servidor, o el ID del usuario encodeado en base64, puede ser adivinado o predecido.
La solución: genera tokens de reset con crypto.randomBytes(32) o equivalente. Guarda el hash del token en la base de datos (no el token en claro), y dale una expiración corta (15–30 minutos).
6. No invalidar sesiones al cambiar contraseña
Si un usuario cambia su contraseña porque sospecha que alguien entró a su cuenta, espera que esa acción cierre todas las sesiones activas. Si no lo hace, el atacante que ya está adentro sigue estando adentro.
La solución: al cambiar contraseña, invalida todos los refresh tokens del usuario y revoca las sesiones activas.
Checklist de autenticación segura
Antes de lanzar cualquier sistema con autenticación:
- Contraseñas hasheadas con bcrypt/Argon2 (factor de costo ≥ 10)
- Tokens JWT con expiración corta (≤ 60 min para access tokens)
- Refresh tokens en cookies HttpOnly
- Cookies con flags Secure, HttpOnly, SameSite
- Rate limiting en login y registro
- Tokens de reset de contraseña con
crypto.randomBytes - Invalidación de sesiones al cambiar contraseña
- Logs de intentos fallidos de autenticación
- HTTPS forzado (sin HTTP permitido)
- Headers de seguridad (HSTS, X-Frame-Options, CSP)
Magic links: una alternativa que subestimamos
Para aplicaciones B2B o dashboards internos, los magic links eliminan la gestión de contraseñas por completo. El usuario ingresa su email, recibe un enlace de un solo uso con expiración de 15 minutos, y accede directamente.
Es más seguro que la mayoría de implementaciones de contraseña que vemos, más fácil de mantener, y elimina el problema de contraseñas débiles o reutilizadas.
Usamos magic links en el panel de administración de este mismo sitio.
Si tienes una aplicación en producción y no estás seguro de cómo está implementada la autenticación, una revisión de seguridad puede identificar vulnerabilidades antes de que alguien más lo haga.
Compartir artículo