Ampliando mi comentario anterior:
Si los dos hashes almacenados (con y sin la transformación de bloqueo de mayúsculas) son iguales, podemos saber que el usuario no tiene letras en su contraseña. (O al menos no tiene letras minúsculas en su contraseña, según cómo realice la transformación).
Dado que Mac y Windows (y Linux) manejan mayúsculas de manera diferente, tendrá que almacenar dos variaciones del hash de transformación de bloqueo de mayúsculas: la inversión de mayúsculas y minúsculas (Windows / Linux) y las mayúsculas (Mac). Ahora podemos determinar aún más acerca de la contraseña de los hashes.
- Si los tres hashes son iguales, el usuario no tiene letras (mayúsculas o minúsculas) en su contraseña.
- Si el hash de transformación de Windows es diferente pero el hash de transformación de Mac es el mismo que el hash principal, entonces el usuario tiene mayúsculas en su contraseña pero no mayúsculas.
- Si los tres hashes son diferentes, el usuario tiene mayúsculas y minúsculas en su contraseña.
Otro pensamiento: ¿es seguro aplicar la misma sal a las tres variaciones? Aunque creo que debería serlo, no veo ninguna ventaja significativa al hacerlo. Si aplica sal diferente a los tres hashes, pienso las filtraciones de información anteriores se niegan. Tenga en cuenta que no soy criptógrafo, aunque no debería haber ninguna fuga de información al incluir tres contraseñas relacionadas y posiblemente idénticas con tres sales diferentes, es posible que se requiera una sal más larga para que esté seguro.
Otros problemas:
Ya que tenemos tres variaciones de hash de contraseña que deben verificarse cada vez que un usuario inicia sesión, se deberán calcular los tres hashes. Si está utilizando bcrypt (o similar) con un número apropiado de rondas de hashing, querrá reducir esa cantidad de rondas para que el tiempo tomado sea aproximadamente 1/3 del valor anterior. (Suponiendo que establezca el número de rondas en el máximo que puede manejar y ahora necesita calcular tres veces el número de hashes por inicio de sesión).
La razón por la que necesita calcular los tres hashes incluso si la primera o la segunda coincidencia es que si no lo hace, habilita la enumeración de credenciales a través de los ataques de tiempo. En teoría, para evitar la enumeración de credenciales, debe proporcionar exactamente la misma respuesta si el usuario no existe o si existe, pero la contraseña es incorrecta. Si devuelve una respuesta idéntica para ambos casos, pero toma milisegundos cuando el usuario no existe y todo un segundo cuando el usuario existe, todavía tiene habilitada la enumeración de credenciales.
Todo hasta ahora, creo que debería ser relativamente seguro si usa diferentes sales para los tres hashes, siempre calcule las tres variaciones de la contraseña suministrada y reduzca el número de rondas para que el tiempo se reduzca en 1/3.
Sin embargo, podría ser más sencillo almacenar solo un hash, verifique que no haya ninguna y el hash no coincida con la contraseña provista por el usuario, sugiérales que pueden tener mayúsculas.
Pensamientos tardíos
No hay necesidad de almacenar tres hashes diferentes como sugerí anteriormente si planea aceptar la transformación de estilo Mac. Solo escribe en mayúsculas todas las contraseñas antes de que estén encriptadas y solo almacena la versión en mayúsculas. Esto también evita los ataques de tiempo ya que solo necesita calcular un hash por inicio de sesión.
Al hacer esto, ha reducido el número de letras / números / símbolos posibles que las personas pueden usar en 26, por lo que puede sugerir que los usuarios utilicen una contraseña ligeramente más larga para compensar.