Cómo se supone que el hash de contraseña de inicio de sesión funciona
Tenga en cuenta que en todos los fragmentos, intencionalmente estoy excluyendo las funciones de seguridad porque quiero mantenerlo compacto. No confíe en estos fragmentos de código para nada.
En las aplicaciones de red habituales, que emplean el hashing de contraseñas, ¿la contraseña del usuario está en el lado del cliente antes de enviarla al servidor o se envía sin hashing como cifrado de la contraseña de texto simple al servidor?
No, está del lado del servidor hash. Usted envía la contraseña a través de texto sin formato, o a través de HTTPS, al servidor. El servidor generará un hash para la contraseña, de esta manera:
public void RegisterAccount(string username, string password, string email)
{
if (!Database.EmailExists(email) && !Database.UsernameExists(username))
{
Database.AddNewUser(username, Hash.GenerateHash(password), email);
}
}
Suponga que Database.AddNewUser(string, string, string);
insertará el nombre de usuario, la contraseña con hash y el correo electrónico en la base de datos. El hash se genera en base a la contraseña.
Digamos que pusiste "no hackearme por favor" como contraseña. bcrypt convertirá eso en $2a$08$BOHyNdXAVkWOUgPG/hvsjew7ZpngqJIgueY6m76xd4y3UllXUZLBy
, o alguna otra variante basada en la sal. La base de datos ahora se ve así:
+--------------+--------------------------------------------------------------+--------------------+
| user | password | email |
+--------------+--------------------------------------------------------------+--------------------+
| markbuffalo | $2a$08$BOHyNdXAVkWOUgPG/hvsjew7ZpngqJIgueY6m76xd4y3UllXUZLBy | [email protected] |
+--------------+--------------------------------------------------------------+--------------------+
Normalmente, llamarás a la base de datos para leer la contraseña de ese nombre de usuario. Una vez que llame a la base de datos, usará una función, como Hash.ValidateHash()
, para ver si coincide. Si coincide, puede iniciar sesión con esa contraseña no hash.
¿Por qué no puedes simplemente pasar el hash para iniciar sesión?
En algunos casos, es muy desafortunado .
La pregunta principal que tengo es si un atacante descubre las contraseñas de hash, ¿por qué no puede simplemente enviar hash al servidor para autenticarse en caso de hashing del lado del cliente?
Esto es posible, pero solo puede suceder durante los casos graves de fallas masivas épicas en nombre de los desarrolladores. De hecho, he visto esto antes, y te mostraré cómo puede suceder esto a través del código:
public void Login(string username, string password)
{
if (Database.LoginMatches(username, password) ||
Database.LoginMatches(username, Hash.ValidateHash(password)))
{
logMeIn();
}
}
En el fragmento de código anterior, el inicio de sesión desea verificar si el usuario tiene el hash o la contraseña que se validará en el hash almacenado en la base de datos. Esta es no la forma correcta de hacerlo. De hecho, es uno de los peores casos de fallas épicas que he visto en mi vida.
Con este código, simplemente puede ingresar el hash o la contraseña e iniciar sesión. Recuerde la tabla anterior. Cualquiera de los siguientes inicios de sesión funcionarán correctamente:
-
Login("markbuffalo", "$2a$08$BOHyNdXAVkWOUgPG/hvsjew7ZpngqJIgueY6m76xd4y3UllXUZLBy");
-
Login("markbuffalo", @"don't hack me please");
Ese es el enfoque incorrecto por completo. No se supone que suceda. A. Todos. Sin embargo, algunos desarrolladores han adoptado este enfoque por razones que no conozco.
¿Cuál es el enfoque correcto para la validación de hash?
Como dijo Rápli András , h(x)
no coincide con h(h(x))
. El enfoque correcto es verificar la contraseña entrante con el hash para ver si coinciden. Si no coinciden, no use ningún OR
magic ( ||
); simplemente no les permita iniciar sesión.