password••••••••Argon2id+salt + cost$argon2id$v=19$m=...$Tk7e...slow, memory-hard, one-way

Hash de contraseña

11 lectura mínimaCriptografía

Almacenar contraseñas de usuario es una de las peores cosas que se pueden hacer en texto sin formato y uno de los errores de seguridad más comunes. La solución ha existido durante décadas (hashing de contraseñas con algoritmos lentos y con poca memoria), pero la diferencia entre implementaciones buenas y malas es enorme, y la mayoría de las filtraciones de datos revelan malas decisiones.

El cuerpo completo del artículo se proporciona en inglés a continuación.

Hashing de contraseñas es la práctica de almacenar una transformación unidireccional de la contraseña de un usuario en lugar de la contraseña misma. Cuando el usuario inicia sesión, se aplica la misma transformación a su entrada y se compara con el valor almacenado. Si se viola la base de datos almacenada, el atacante tiene hashes, no contraseñas, y recuperar los originales debería ser computacionalmente inviable.

Esa es la teoría. La práctica varía desde "funciona como se anuncia" hasta "también podría haber sido texto sin formato", dependiendo del algoritmo y los parámetros elegidos.

Qué necesita un buen hash de contraseña

  • Unidireccional. Conocer el hash no debería revelar nada útil sobre la contraseña.
  • Salted. Cada usuario tiene una sal aleatoria única mezclada con el hachís. Impide tablas Rainbow precalculadas y garantiza que contraseñas idénticas produzcan hashes diferentes.
  • Slow. Un cálculo de hash único debería tomar una fracción significativa de segundo en el hardware del atacante. La fuerza bruta a miles de millones por segundo es lo que derrota a los hashes rápidos.
  • Memoria dura. Cada hash debería requerir una RAM significativa, derrotando la paralelización de GPU y ASIC que prospera con una memoria pequeña por instancia.
  • Parámetros preparados para el futuro. Los factores de costo deben poder ajustarse hacia arriba a medida que el hardware crece más rápido.

Las elecciones equivocadas

Algoritmos que nunca debes usar para el almacenamiento de contraseñas:

  • MD5. Criptográficamente roto desde 2004. Fuerza bruta a decenas de miles de millones de hashes por segundo en el consumidor hardware.
  • SHA-1, SHA-256. Hashes criptográficos rápidos diseñados para comprobar la integridad, no para almacenar contraseñas. Fuerza bruta a miles de millones por segundo en GPU.
  • Contraseñas cifradas. Si puede descifrarlas en texto plano, un atacante que robe la clave también podrá hacerlo. El hash es la respuesta; el cifrado no lo es.
  • Plaintext. Todavía sucede en 2026. Cada violación de contraseña de texto sin formato es ingeniería evitable.

Las opciones correctas

Los tres algoritmos modernos recomendados:

  • bcrypt (1999). Factor de coste ajustable (rondas de cómputo). Limitado a contraseñas de 72 bytes. No tiene mucha memoria, por lo que las GPU pueden atacarla de manera eficiente, pero un factor de costo razonable aún hace que los ataques sean costosos. Amplia implementación, fácil de usar correctamente.
  • scrypt (2009). Duro como la memoria. Costo de memoria configurable, paralelismo y costo de CPU. Más complejo que bcrypt; a veces mal configurado.
  • Argon2 (ganador del concurso de hash de contraseñas de 2015). Tres variantes: Argon2d (dependiente de datos, resistente a ataques de GPU pero vulnerable a canales laterales), Argon2i (independiente de datos, resistente a canales laterales), Argon2id (híbrido: el valor predeterminado recomendado). Moderno, bien examinado, la elección correcta para sistemas nuevos.

OWASP actualmente recomienda Argon2id con al menos 19 MB de memoria, número de iteraciones de 2 y paralelismo de 1. Para sistemas donde Argon2 no está disponible, bcrypt con un costo ≥ 10 o scrypt con los parámetros apropiados son alternativas aceptables.

Qué significa "lento" en práctica

El factor de costo de 10 en bcrypt significa aproximadamente 100 ms por hash en hardware moderno. Para un usuario legítimo que inicia sesión, esto es imperceptible. Para un atacante que intenta forzar 100 millones de contraseñas de una base de datos filtrada, son 100 millones × 100 ms = 116 días de tiempo de GPU por paso a través de una lista de palabras razonable. Combinadas con una sal única por usuario, las tablas de arco iris grandes son inútiles.

Para un hash rápido como SHA-256 sin sal, la misma operación toma unos minutos en el mismo hardware.

Manejo de sal

  • La sal es por usuario, generada por un CSPRNG en la creación del usuario
  • 16 bytes es suficiente (128 bits de aleatoriedad)
  • Salt se almacena junto con el hash, no es secreto: su trabajo es ser único, no oculto
  • La mayoría de las bibliotecas de hash modernas (bcrypt, salidas Argon2 en formato de cadena PHC) agrupan algoritmos, parámetros, salt y hash en una sola cadena

Pepper: opcional extra

A pepper es un valor secreto de todo el sitio agregado a la entrada hash, almacenado por separado de la base de datos (en un HSM, un almacén de claves o una configuración de aplicación). Si se vuelca la base de datos pero no el pepper, los hashes son irrecuperables incluso con el salt del usuario, porque el atacante no tiene el pepper. Pepper es un complemento útil para sistemas de alto valor.

Actualización de hashes de forma segura

Cuando cambia parámetros o migra algoritmos, no puede volver a realizar hash sin la contraseña original. El enfoque estándar:

  1. Cada registro de usuario almacena su algoritmo hash actual, parámetros, sal y hash.
  2. Al iniciar sesión, verifique el hash almacenado con sus parámetros originales.
  3. Si la verificación se realiza correctamente y los parámetros están desactualizados, vuelva a realizar el hash con los parámetros actuales y actualice el registro.

A los pocos meses de usuarios activos, el la base de datos realiza transiciones a nuevos parámetros sin forzar el restablecimiento de contraseñas.

Qué significa esto para los usuarios

Para los usuarios finales, el efecto práctico: incluso cuando se viola una base de datos, una contraseña única y segura (administrada por un administrador de contraseñas ) más un buen hash en el servidor significa que la contraseña permanece efectivamente secreta. Las contraseñas débiles se descifran incluso en bases de datos bien codificadas; el usuario es la variable que un desarrollador no puede controlar.

Preguntas frecuentes

¿Por qué bcrypt está limitado a 72 caracteres?
Detalle de implementación histórica del cifrado Blowfish subyacente. Las entradas más largas se truncan. La mayoría de los usuarios no se dan cuenta; una frase de contraseña aleatoria de 16 caracteres está muy por debajo del límite. Para los sistemas que desean una longitud de contraseña ilimitada, Argon2 no tiene tal restricción.
¿Debería salpimentar mis contraseñas?
Se requiere Salt (y cualquier biblioteca acreditada lo hace automáticamente). Pepper es opcional pero valioso para sistemas de alta seguridad. La contrapartida: gestionar el pimiento como un secreto a largo plazo fuera de la base de datos añade complejidad operativa. La mayoría de las aplicaciones almacenan sal + hachís; los más grandes almacenan sal + picadillo + picadillo derivado de pimienta.
¿Argon2 siempre es mejor que bcrypt?
Para sistemas nuevos, sí. Argon2 tiene memoria dura (resistente a GPU/ASIC), no tiene límite de 72 caracteres y ganó el concurso de hash de contraseñas por buenas razones. bcrypt sigue siendo aceptable cuando Argon2 no está disponible o las limitaciones organizativas prefieren el estándar anterior. Para los sistemas heredados que utilizan bcrypt con un costo ≥ 10, la urgencia de migrar es baja.
¿Cuánto tiempo debería llevar hacer hash de una contraseña?
OWASP sugiere entre 100 y 500 ms en el hardware del servidor. Más rápido significa más débil contra los atacantes; la lentitud comienza a afectar la experiencia de inicio de sesión legítima. El número correcto depende de su tráfico: los servicios de gran volumen eligen un costo más bajo; Los servicios de alta seguridad con bajas tasas de inicio de sesión pueden elegir más.
¿Puedo almacenar contraseñas cifradas en lugar de hash?
No. El cifrado es reversible, lo que significa que la clave de cifrado debe existir en algún lugar al que pueda acceder la aplicación. Si se viola la base de datos, la clave a menudo también lo es, y efectivamente se ha almacenado texto sin formato. La cuestión es la irreversibilidad del hash: ni siquiera su propia aplicación puede recuperar la contraseña, que es una propiedad de seguridad.
Explicación del hash de contraseñas: por qué son importantes bcrypt, scrypt y Argon2