Tema 15
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.
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.
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.
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.
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.
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.
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.
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.
| Elemento | Debe ser único por usuario | Debe ser secreto | Se guarda junto al hash |
|---|---|---|---|
| Sal | Sí | No | Sí |
| Pepper | No necesariamente | Sí | No |
Ambos pueden coexistir, pero cumplen funciones diferentes.
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.
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.
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.
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.
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:
En práctica general, Argon2 suele verse como una de las opciones más recomendables cuando está disponible.
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.
La elección depende del entorno, la biblioteca disponible, requisitos de compatibilidad y madurez operativa. En términos generales:
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.
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.
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.
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.
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.