Salting de contraseñas - Por qué el hashing solo no es suficiente
Lectura de 2 min aprox.
La sal (salt) son datos aleatorios que se añaden al aplicar un hash a una contraseña. Como una misma contraseña genera un valor hash distinto cuando la sal es diferente, la sal neutraliza los ataques de tablas arcoíris y los ataques de precálculo. La sal se genera de forma única para cada usuario y se almacena junto con el valor hash.
Cómo funciona la sal, con un ejemplo numérico
Al aplicar el hash a una contraseña, la sal se genera con un generador de números aleatorios criptográficamente seguro y se combina con la contraseña antes de introducirla en la función hash. Por ejemplo, añadir una sal de 16 bytes (128 bits) a la contraseña «mypassword» produce un valor hash completamente distinto para cada usuario, incluso con la misma contraseña. La longitud recomendada de la sal es de al menos 16 bytes; el estándar es de 128 bits en bcrypt y de al menos 128 bits en Argon2. A fecha de 2025, las directrices de OWASP recomiendan combinar Argon2id con una sal de al menos 16 bytes. La sal no necesita mantenerse en secreto y se almacena en la base de datos junto con el valor hash. Lo importante es usar una sal diferente para cada usuario.
| Usuario | Sal (16 bytes, primeros 8 dígitos) | Primeros 16 dígitos del hash |
|---|---|---|
| Usuario A (sin sal) | Ninguna | 89e01536ac207279... |
| Usuario B (sin sal) | Ninguna | 89e01536ac207279... |
| Usuario A (con sal) | 8f2b7c1d... | 58ef28c75d1f8e9e... |
| Usuario B (con sal) | 1a4c9e2b... | f8250873b0d4600e... |
Las dos filas sin sal terminan con el mismo valor, y eso es precisamente lo que hace que las tablas rainbow funcionen. Las dos filas inferiores, cada una con una sal distinta por usuario, producen valores sin nada en común aunque la contraseña sea idéntica.
Cómo migrar un sistema existente que no usa sal
Al migrar un sistema existente desde un almacenamiento sin sal, los valores hash ya guardados no pueden regenerarse tal cual. Como un hash no se puede revertir, el servicio no conserva las contraseñas en texto claro de los usuarios y, por tanto, no tiene a mano el material con el que calcular los hashes del nuevo esquema. Por eso la migración avanza esperando a que el usuario inicie sesión la próxima vez e introduzca la contraseña correcta, para generar con ese valor un hash del nuevo esquema y sustituir el registro antiguo. No se completa en una sola operación: el reemplazo progresa con el tiempo, en proporción a la frecuencia con la que los usuarios inician sesión. Los registros de los usuarios que no han iniciado sesión durante un periodo largo permanecen en el esquema antiguo, de modo que se hacen necesarias decisiones como fijar un plazo y exigir el restablecimiento de la contraseña. Como durante la migración coexisten en la base de datos el esquema antiguo y el nuevo, el diseño también necesita una forma de saber, a partir del registro, con qué esquema se guardó cada entrada. Cuando se sigue operando sin sal, el tiempo que requiere esta migración es en sí mismo un factor que condiciona la magnitud del daño en caso de filtración.
Por qué es necesaria la sal
Sin una sal, todos los usuarios que usan la misma contraseña terminan con el mismo valor hash. Un atacante puede usar una tabla arcoíris para descifrar grandes cantidades de contraseñas a la vez. En cifras concretas, sin una sal un atacante puede atacar la contraseña de cada usuario con una sola tabla arcoíris (del orden de unos cientos de GB). Sin embargo, al usar una sal de 16 bytes, en teoría se necesitarían 2 elevado a la 128 tablas, lo que hace que los ataques de precálculo sean prácticamente imposibles.
Errores frecuentes en la práctica
Un error común es usar la misma sal para todos los usuarios, lo que reduce enormemente la eficacia para neutralizar las tablas arcoíris. Asimismo, si la sal es demasiado corta (como de 4 bytes o menos), un atacante puede crear tablas que cubran todos los patrones de sal. Otro error es intentar mantener la sal en «secreto» guardándola en un lugar aparte. El propósito de la sal es garantizar la unicidad, no el secreto, por lo que no hay problema en almacenarla en la misma base de datos que el valor hash. Las contraseñas generadas aleatoriamente ya son difíciles de adivinar de por sí, pero combinarlas con una implementación de sal adecuada en el lado del servicio logra una protección aún más robusta.
¿Te resultó útil este artículo?