El propósito único de la sal es ser único : no hay dos contraseñas con hash que usen el mismo valor de sal. Esto tiene por objeto evitar el costo compartido, como las tablas hash precalculadas.
La singularidad debe ser mundial . Por ejemplo, supongamos que usaste un contador simple como sal. En consecuencia, el valor "1" se usará como sal para la primera cuenta creada, probablemente para el administrador del servidor. Esto será cierto para todas instancias instaladas de ese servidor. Esto hace que valga la pena calcular una tabla grande (por ejemplo, una rainbow table ) de posibles contraseñas con hash que usan "1" como sal, porque esa tabla podría usarse para atacar la contraseña del administrador en todos los servidores que usan ese software. La palabra para meditar aquí es "vale la pena".
Dado que la singularidad de a nivel de servidor no es suficiente, un contador no será suficiente; el nombre de usuario tampoco es un buen salt (los nombres de usuario son únicos en un servidor determinado, pero hay muchos 'Bob', 'Joe' y 'DarkLord42' por ahí). Un UUID (GUID) debe hacer el truco. También puede usar un generador pseudoaleatorio fuerte y uniforme ( /dev/urandom
, CryptGenRandom()
, java.security.SecureRandom
... dependiendo de la plataforma que use) y obtener suficientes bytes aleatorios para que los riesgos de reutilizar un valor de sal sean lo suficientemente pequeños; 16 bytes son suficientes para eso. El uso de la aleatoriedad es la "forma robusta" porque produce unicidad con una probabilidad suficientemente alta, sin tener que depender de las convenciones mundiales.