Codea Seguro Codea Seguro
Desarrollo Seguro Dificultad: basica

Autenticación y almacenamiento de contraseñas

Cómo guardar contraseñas, exigir buenos factores y frenar ataques de fuerza bruta.

Las contraseñas son el eslabón más atacado de la autenticación. Guardarlas o verificarlas mal convierte una base de datos filtrada en un desastre total.

1. Nunca guardes contraseñas en claro ni con hash rápido

MD5, SHA-1 y SHA-256 no sirven para contraseñas: son demasiado rápidos y se rompen con GPUs. Usa un algoritmo de hashing diseñado para contraseñas, con salt por usuario:

// MAL — hash rápido, sin salt, reversible en masa
const hash = crypto.createHash('sha256').update(password).digest('hex');

// BIEN — argon2id (o bcrypt/scrypt) con salt y coste ajustable
import argon2 from 'argon2';

const hash = await argon2.hash(password, { type: argon2.argon2id });
const ok = await argon2.verify(hash, password);

Preferencia: argon2id > scrypt > bcrypt. Nunca cifrado reversible.

2. Mide la fortaleza, no impongas reglas absurdas

Las reglas tipo “una mayúscula, un número y un símbolo” producen contraseñas predecibles (Password1!). Mejor:

  • Exige longitud mínima (≥ 12 caracteres) y permite frases largas.
  • Rechaza contraseñas filtradas con una lista como Have I Been Pwned (k-anonymity).
  • No limites el máximo de forma agresiva ni prohíbas pegar.

3. Activa MFA

Un segundo factor (TOTP, WebAuthn/passkeys) neutraliza la mayoría de robos de credenciales. Prioriza passkeys/WebAuthn sobre SMS, que es vulnerable a SIM swapping.

4. Frena la fuerza bruta

  • Rate limiting por IP y por cuenta en el endpoint de login.
  • Backoff exponencial y bloqueo temporal tras varios intentos.
  • Mensajes de error genéricos: no reveles si fue el usuario o la contraseña lo que falló.

5. Protege el reseteo de contraseña

  • Tokens de un solo uso, de vida corta y aleatorios (≥ 128 bits).
  • No reveles si un correo existe (“si la cuenta existe, enviamos un enlace”).
  • Invalida sesiones activas al cambiar la contraseña.

Checklist rápida

  • Hashing con argon2id/bcrypt/scrypt y salt por usuario.
  • Longitud mínima ≥ 12; sin reglas de composición contraproducentes.
  • Bloqueo de contraseñas filtradas conocidas.
  • MFA disponible, con preferencia por passkeys/WebAuthn.
  • Rate limiting y backoff en login; errores genéricos.
  • Reseteo con tokens de un solo uso y expiración corta.