Cómo se guardan las contraseñas: del texto plano a Argon2
Los servicios no guardan tu contraseña tal como la escribiste. Este es el ascenso de treinta años del texto plano al hash, a la sal y a los KDF lentos, y lo que enseñó la filtración de LinkedIn de 2012.
Cuando inicias sesión, lo único que un servicio necesita decidir es si la contraseña que conoces es la misma que elegiste al registrarte. La forma tentadora de comprobarlo —escribir la contraseña en una base de datos y compararla— significa que, en cuanto esa base de datos se filtra, todas las cuentas quedan abiertas. Así que a lo largo de unos treinta años la industria descubrió cómo verificar una contraseña sin conservar el original. Esta es esa escalera, peldaño a peldaño.
Paso 0: texto plano — por qué falla
Guardar las contraseñas tal cual falla de dos maneras. Primero, cualquier persona interna o intrusa que lea la base de datos conoce al instante todos los secretos. Segundo, como la gente reutiliza la misma contraseña en varios sitios, una sola filtración alimenta los ataques de relleno de credenciales: se reprueba la lista filtrada contra bancos y proveedores de correo. La idea de partida es que ningún servicio necesita de verdad conocer tu contraseña original.
Paso 1: hash — no conservar el original
Una función hash convierte cualquier entrada en un valor de tamaño fijo del que no se puede recuperar la entrada. Así, un servicio puede guardar solo el hash al registrarte, calcular el hash de lo que escribes al entrar y comparar ambos, verificándote sin conservar el original. Los sistemas Unix lo hacían desde muy pronto.
El problema fue usar un hash rápido. MD5 y SHA-1 se diseñaron para ser lo más rápidos posible al verificar archivos. Quien tenga una lista filtrada de esos hashes puede calcular el hash de miles de millones de contraseñas comunes por segundo y buscar coincidencias. Ver caer casi al instante una contraseña corta en el descifrador de hashes del sitio hace tangible esa debilidad. Peor aún: la misma contraseña siempre da el mismo hash, así que los atacantes podían precalcular una tabla enorme de búsqueda —una rainbow table— y revertir muchos hashes de golpe.
Paso 2: sal — vencer la precomputación
Una sal es un valor aleatorio distinto añadido a cada contraseña. Mezclar la sal antes de calcular el hash hace que dos usuarios con la misma contraseña obtengan valores guardados distintos, lo que neutraliza las rainbow tables: habría que construir una tabla nueva por cada sal, y con una sal distinta por usuario, una sola tabla no puede romper muchas cuentas.
Las sales no son secretas: suelen guardarse justo al lado del hash. Su función es impedir que un solo cálculo rompa muchas cuentas a la vez, no permanecer ocultas. La propiedad se ve directamente en el generador de hash: antepón un valor distinto al mismo texto y el resumen cambia por completo.
LinkedIn 2012: qué pasa sin sal
En junio de 2012 aparecieron en línea los hashes de unos 6,5 millones de contraseñas de LinkedIn. Eran SHA-1 sin sal. Sin sal, las rainbow tables públicas y los ataques de diccionario se aplicaron directamente, y cientos de miles cayeron en días. En 2016, más de 117 millones de registros de cuentas, supuestamente de la misma filtración, se pusieron de nuevo a la venta. LinkedIn pasó después a usar sal y hashing lento y llegó a un acuerdo en una demanda colectiva. Sigue siendo la demostración de manual de por qué un almacenamiento «con hash pero sin sal» no basta.
Paso 3: KDF lentos — ser rápido era el problema
Incluso con sal, queda un problema: el propio hash es demasiado rápido. Eso motivó funciones de contraseña específicas y deliberadamente lentas, conocidas como funciones de derivación de claves (KDF).
- bcrypt (1999): presentada por Niels Provos y David Mazières. Lleva un factor de coste; subirlo en uno duplica el trabajo. A medida que el hardware acelera, basta subir el coste para seguir el ritmo, y por eso el artículo la llamó «adaptable al futuro». Se percibe cambiando el coste en el generador de hash bcrypt.
- scrypt (2009): diseñada por Colin Percival y luego descrita en el RFC 7914. Es deliberadamente exigente en memoria además de lenta, lo que encarece mucho los ataques masivamente paralelos en hardware con poca memoria (ASIC, GPU).
- Argon2 (2015): ganadora de la Password Hashing Competition abierta. Permite ajustar memoria, tiempo y paralelismo por separado, y su variante Argon2id, resistente a canales laterales, es hoy el valor recomendado por defecto para sistemas nuevos.
La clave es la asimetría. El inicio de sesión de un usuario real puede permitirse un cuarto de segundo, pero un atacante debe multiplicar ese cuarto de segundo por cientos de millones de hashes filtrados, algo que pronto resulta inasumible.
Dónde está el listón ahora: NIST y OWASP
Las Directrices de Identidad Digital del NIST (SP 800-63B, revisión de 2025) indican que las contraseñas guardadas deben llevar sal y hashearse con un esquema adecuado, con una sal de al menos 32 bits y un factor de coste tan alto como permita el rendimiento. Además recomiendan un paso adicional con clave, un secreto que solo conoce el verificador: un pepper. La Password Storage Cheat Sheet de OWASP da cifras concretas: Argon2id con al menos 19 MiB de memoria, 2 iteraciones y 1 grado de paralelismo; scrypt (coste 2^17) donde Argon2 no esté disponible; y para sistemas heredados, bcrypt con un factor de trabajo de 10 o más.
El consejo sobre las contraseñas que eligen los usuarios también cambió: priorizar la longitud sobre las reglas de composición que obligan a mezclar tipos de caracteres, y no exigir cambios periódicos. Por qué gana la longitud se ve mejor en el generador de contraseñas, donde la entropía en bits sube con cada carácter añadido.
Sal, pepper y una confusión habitual
Se suelen mezclar tres ideas. Una sal es única por contraseña, se guarda junto al hash y sirve para inutilizar la precomputación y los ataques entre cuentas. Un pepper es un único valor secreto compartido por todas las contraseñas pero guardado fuera de la base de datos —en la configuración de la aplicación o en un módulo de seguridad de hardware—, de modo que una filtración solo de la base de datos (la más común) no entregue a los atacantes todo lo que necesitan. Si se filtran ambos, el pepper no aporta nada; por eso debe vivir donde el volcado de la base de datos no llegue.
La otra confusión es «hash» frente a «cifrado». El cifrado es reversible por diseño: con la clave recuperas el texto plano. El hash es de un solo sentido, y esa irreversibilidad es justo el objetivo con las contraseñas: un servicio nunca debería poder enviarte por correo tu contraseña antigua, solo restablecerla. Si un sitio puede mostrarte tu contraseña actual, la guardó de forma reversible, que es la señal de alarma del Paso 0.
Actualizar hashes viejos sin restablecer contraseñas
Una preocupación frecuente es que adoptar un KDF lento obligue a que todos restablezcan la contraseña. No es así. La migración estándar calcula el hash del hash ya guardado con la nueva función; por ejemplo, envolver los viejos SHA-1 sin sal como bcrypt(sha1_hash) con una sal y un coste nuevos. Cada registro se vuelve fuerte de inmediato y, cuando el usuario vuelve a entrar, puedes recalcular de forma transparente el hash de su contraseña real con el esquema moderno y quitar la envoltura. Subir después el factor de coste de bcrypt funciona igual: recalcular al iniciar sesión y reemplazar. Como los parámetros (coste, sal, algoritmo) viajan dentro de la cadena guardada, el verificador siempre sabe cómo se creó cada registro y compara correctamente durante la transición.
La versión breve
La historia del almacenamiento de contraseñas se resume en tres movimientos: no conservar el original, vencer la precomputación y encarecer cada intento. Cada paso tapó el agujero que dejó el anterior, y los servicios que se saltaron uno —LinkedIn en 2012— lo pagaron. Si construyes algo hoy, la respuesta está zanjada: Argon2id (o bcrypt/scrypt según las circunstancias) con una sal por usuario, y usuarios animados a elegir contraseñas largas y aleatorias.
Fuentes
- NIST SP 800-63B — Digital Identity Guidelines: Authentication (v4.0, 2025)
- OWASP — Password Storage Cheat Sheet
- Provos & Mazières — A Future-Adaptable Password Scheme (USENIX 1999)
- RFC 7914 — The scrypt Password-Based Key Derivation Function
- Password Hashing Competition — Argon2 (2015)
- Sophos News — LinkedIn settles class action over 2012 unsalted password leak