Tema 15

15. Almacenamiento seguro de contraseñas: sal, pepper, stretching y Argon2, bcrypt, scrypt, PBKDF2

Proteger contraseñas no consiste en cifrarlas ni en aplicarles cualquier hash rápido. El almacenamiento seguro de contraseñas es un problema específico con amenazas propias: filtraciones de bases de datos, fuerza bruta, ataques por diccionario y hardware especializado. Por eso requiere técnicas y algoritmos diseñados especialmente para volver costoso cada intento de adivinación.

Objetivo Entender cómo se almacenan contraseñas de forma segura
Enfoque Práctico, defensivo y orientado a ataques reales
Resultado Distinguir entre hashing común y password hashing adecuado

15.1 Introducción

Cuando un sistema autentica usuarios con contraseña, no debería guardar esas contraseñas en texto plano. Si la base de datos se filtra, el atacante obtendría acceso inmediato a todas las cuentas y, además, a posibles reutilizaciones de esas contraseñas en otros servicios.

Pero tampoco alcanza con aplicar un hash común como SHA-256 y guardar el resultado. El problema del almacenamiento de contraseñas tiene requisitos particulares: el sistema debe verificar rápidamente una contraseña válida para el usuario legítimo, pero debe hacer muy costoso para un atacante probar millones o miles de millones de intentos.

15.2 Qué problema queremos resolver

El objetivo no es recuperar la contraseña original, sino verificar si la contraseña ingresada por el usuario coincide con la que se usó durante el registro. Para eso, el sistema puede procesar la contraseña ingresada con el mismo esquema y comparar el resultado almacenado.

Si la base de datos se filtra, el atacante no debería poder derivar fácilmente las contraseñas originales a partir de los valores almacenados. Eso requiere un diseño pensado específicamente contra ataques offline.

15.3 Por qué no se deben usar hashes rápidos comunes

Funciones hash como SHA-256 o SHA-512 son excelentes para integridad, firmas o HMAC, pero son demasiado rápidas para contraseñas. Esa velocidad beneficia también al atacante, que puede probar enormes cantidades de candidatos por segundo usando CPU, GPU, FPGA o hardware especializado.

Una contraseña humana suele tener poca entropía comparada con una clave criptográfica aleatoria. Por eso el sistema debe compensar esa debilidad haciendo que cada intento de verificación sea deliberadamente caro.

15.4 Ataques offline

El escenario más peligroso es la filtración de la base de datos de credenciales. En ese caso, el atacante ya no depende de límites de tasa del sistema ni de intentos en línea. Puede trabajar sin restricciones desde sus propios equipos, probando diccionarios, combinaciones comunes y ataques exhaustivos.

Todo el diseño de password hashing busca hacer ese trabajo lo más costoso posible.

15.5 Qué es password hashing

Password hashing es el uso de funciones especialmente diseñadas para derivar un valor almacenable a partir de una contraseña, introduciendo costo computacional y, en muchos casos, costo de memoria. La idea es que verificar una contraseña legítima siga siendo factible para el sistema, pero atacar masivamente millones de hashes sea caro para el adversario.

No se trata solo de aplicar un hash, sino de aplicar un esquema lento y endurecido.

15.6 La sal

La sal es un valor aleatorio único por contraseña o por registro, que se combina con la contraseña antes de aplicar el algoritmo. Su objetivo principal es impedir que dos usuarios con la misma contraseña tengan el mismo resultado almacenado y evitar ataques masivos con tablas precalculadas.

La sal no necesita ser secreta. Puede almacenarse junto al hash. Lo importante es que sea distinta para cada contraseña y generada con buena aleatoriedad.

La sal no hace fuerte una contraseña débil, pero evita que una debilidad individual se explote masivamente de forma trivial.

15.7 Qué problemas resuelve la sal

  • Evita que dos usuarios con la misma contraseña tengan el mismo hash almacenado.
  • Dificulta el uso de tablas rainbow o tablas precalculadas.
  • Obliga al atacante a trabajar por cada hash individual.
  • Reduce la visibilidad inmediata de patrones repetidos en una base filtrada.

15.8 Qué es el pepper

El pepper es un secreto adicional que se combina con la contraseña o con el resultado derivado, pero que no se almacena en la misma base de datos que los hashes. A diferencia de la sal, el pepper sí debe mantenerse secreto y suele guardarse en un HSM, un vault de secretos o una variable de entorno protegida.

Su objetivo es añadir una capa adicional de defensa en caso de filtración parcial, especialmente si el atacante obtiene la base de datos pero no el entorno de secretos.

15.9 Diferencia entre sal y pepper

Elemento Debe ser único por usuario Debe ser secreto Se guarda junto al hash
Sal No
Pepper No necesariamente No

Ambos pueden coexistir, pero cumplen funciones diferentes.

15.10 Stretching o endurecimiento

Stretching significa aumentar artificialmente el costo de procesar una contraseña mediante múltiples iteraciones, mayor trabajo computacional o consumo significativo de memoria. El objetivo es simple: que cada intento del atacante sea caro.

Como los usuarios no cambian la contraseña en cada operación de red de forma masiva, el sistema puede permitirse un costo razonable por verificación. El atacante, en cambio, quiere probar millones de candidatos. Ahí aparece la ventaja defensiva.

15.11 PBKDF2

PBKDF2 es uno de los esquemas más antiguos y extendidos para derivación de claves y password hashing. Su enfoque principal es el endurecimiento mediante iteraciones repetidas de una función pseudoaleatoria basada habitualmente en HMAC.

Su gran ventaja es la estandarización y compatibilidad. Su limitación es que no fue diseñado para ser memory-hard, por lo que frente a hardware moderno puede resultar menos resistente que alternativas más recientes si no se parametriza cuidadosamente.

15.12 bcrypt

bcrypt fue durante mucho tiempo una de las opciones preferidas para contraseñas. Se basa en Blowfish y permite ajustar un factor de costo que incrementa el trabajo computacional requerido.

Su fortaleza principal es haber sido diseñado específicamente para password hashing, no como una simple reutilización de un hash rápido. Aunque hoy existen alternativas más modernas, bcrypt sigue siendo una opción razonable en muchos sistemas si se configura correctamente.

15.13 scrypt

scrypt introdujo una mejora importante: además de ser costoso en tiempo, busca ser costoso en memoria. Esto dificulta ataques masivos con hardware paralelo especializado, porque no basta con tener muchos núcleos; también se necesita memoria significativa para cada intento.

Esa propiedad memory-hard lo convirtió en una evolución relevante respecto de enfoques puramente iterativos.

15.14 Argon2

Argon2 es considerado hoy una de las referencias modernas más importantes para password hashing. Fue el ganador del Password Hashing Competition y fue diseñado precisamente para resistir ataques contemporáneos, incluyendo escenarios con hardware especializado.

Permite ajustar tres dimensiones clave:

  • Costo de memoria.
  • Costo de tiempo.
  • Grado de paralelismo.

En práctica general, Argon2 suele verse como una de las opciones más recomendables cuando está disponible.

15.15 Argon2i, Argon2d y Argon2id

Argon2 tiene variantes con perfiles distintos. Sin entrar en excesivo detalle, Argon2id suele considerarse una elección equilibrada en muchos contextos prácticos, porque combina propiedades útiles frente a distintos tipos de amenazas y es la variante frecuentemente recomendada para contraseñas.

15.16 Cómo elegir entre Argon2, bcrypt, scrypt y PBKDF2

La elección depende del entorno, la biblioteca disponible, requisitos de compatibilidad y madurez operativa. En términos generales:

  • Argon2: opción moderna muy sólida cuando está disponible.
  • bcrypt: ampliamente usado y razonable si se configura bien.
  • scrypt: valioso por su dureza en memoria.
  • PBKDF2: útil por compatibilidad y estándares, pero en muchos contextos menos preferible que Argon2 o scrypt frente a hardware moderno.

15.17 Parámetros importan tanto como el algoritmo

No alcanza con decir "uso Argon2" o "uso bcrypt". Si los parámetros de costo son demasiado bajos, la protección puede ser insuficiente. Y si son excesivos sin criterio, el sistema puede sufrir problemas operativos o de rendimiento.

La configuración debe calibrarse según el contexto real: capacidad del servidor, volumen de autenticaciones, tipo de amenaza y necesidades de actualización futura.

15.18 Migración y rehash

Un sistema maduro no asume que su configuración será adecuada para siempre. A medida que mejora el hardware, pueden necesitarse parámetros más altos o incluso un algoritmo distinto. Por eso es buena práctica diseñar mecanismos de rehash progresivo, donde las contraseñas se recalculan con parámetros actualizados cuando el usuario vuelve a autenticarse.

15.19 Qué no debe hacerse

  • Guardar contraseñas en texto plano.
  • Aplicar MD5, SHA-1 o SHA-256 directamente como único mecanismo.
  • Reutilizar la misma sal para todos los usuarios.
  • Usar parámetros por defecto sin evaluarlos.
  • Confiar en que la base de datos nunca se filtrará.
  • Ocultar decisiones inseguras detrás de la palabra "encriptado".

15.20 Qué ocurre si la base se filtra

Si el sistema está bien diseñado, una filtración de la base de hashes no debería dar acceso inmediato a las contraseñas. El atacante todavía deberá enfrentar el costo individual de romper cada registro, condicionado por la fortaleza de la contraseña, el uso de sal, la presencia de pepper y el costo del algoritmo.

La meta no es hacer imposible todo ataque, sino volverlo suficientemente caro, lento y limitado como para reducir enormemente el impacto.

15.21 Contraseñas débiles siguen siendo un problema

Ningún esquema de almacenamiento puede convertir una contraseña extremadamente débil en una contraseña segura. Si el usuario elige un secreto trivial, el atacante podrá eventualmente encontrarlo con diccionarios o combinaciones comunes. El password hashing mitiga el daño, pero no reemplaza políticas de calidad, MFA y defensa en profundidad.

15.22 Buenas prácticas actuales

  • Usar Argon2id cuando sea viable y esté bien soportado.
  • Usar bcrypt o scrypt como alternativas razonables según el entorno.
  • Usar una sal aleatoria única por registro.
  • Considerar pepper como capa adicional si puede gestionarse correctamente.
  • Ajustar parámetros de costo con criterio y revisarlos periódicamente.
  • Diseñar migraciones y rehash hacia configuraciones más fuertes.

15.23 Errores conceptuales frecuentes

  • Creer que "hacer SHA-256 a la contraseña" ya es suficiente.
  • Confundir sal con secreto.
  • Pensar que pepper reemplaza a la sal.
  • Suponer que un algoritmo fuerte compensa contraseñas muy pobres.
  • Elegir parámetros de costo sin medir ni revisar.

15.24 Qué debes recordar de este tema

  • Las contraseñas no deben almacenarse en texto plano ni con hashes rápidos comunes como único mecanismo.
  • El password hashing busca volver costoso cada intento de adivinación offline.
  • La sal debe ser única por registro y no necesita ser secreta.
  • El pepper es un secreto adicional externo a la base de datos.
  • Argon2, bcrypt, scrypt y PBKDF2 son esquemas pensados para este problema, con ventajas y perfiles distintos.
  • El algoritmo y sus parámetros importan, pero no sustituyen contraseñas razonables ni otras defensas.

15.25 Conclusión

El almacenamiento seguro de contraseñas es un caso clásico donde usar la herramienta "criptográfica correcta" marca una diferencia radical. No se trata solo de aplicar un hash, sino de resistir filtraciones reales, ataques offline y hardware especializado con técnicas diseñadas específicamente para ese escenario.

En el próximo tema estudiaremos MAC y HMAC, mecanismos que toman las funciones hash y las combinan con claves para lograr autenticación e integridad de mensajes.