¿Cómo funciona el almacenamiento de contraseñas de hash? [duplicar]

27

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 sin formato al servidor?

La pregunta principal que tengo es si un atacante descubre las contraseñas de hash, ¿por qué no pueden enviar hash al servidor para autenticarse en caso de hashing del lado del cliente?

    
pregunta Allahjane 13.04.2016 - 18:31
fuente

5 respuestas

39

Al menos una parte del hashing debe ocurrir en el lado del servidor. De hecho, lo que sea que el cliente envíe al servidor otorga acceso, por lo tanto, si ese mismo valor se almacena tal como está en el servidor, entonces tiene los mismos problemas que el almacenamiento de contraseña en texto sin formato, es decir, un solo vistazo en su servidor. La base de datos da todos los accesos.

En la mayoría de los casos todo el hashing se realiza en el servidor, ya que el cliente es un navegador web que, en el mejor de los casos, puede hacer algo de Javascript, y Javascript no es muy bueno en tareas criptográficas. El cliente envía la contraseña (a través de HTTPS, por supuesto), y el servidor calcula el hash y lo compara con el valor de hash almacenado. El atacante no puede simplemente "pasar el hash"; debe enviar un valor que, cuando el servidor lo hable, genera el valor de hash almacenado.

Si los clientes son buenos para crear criptografía (por ejemplo, un cliente nativo pesado para un juego), entonces la mayor parte del proceso de hashing se puede hacer en el lado del cliente, pero aún debe haber un cálculo final de hash en el servidor.

    
respondido por el Thomas Pornin 13.04.2016 - 18:42
fuente
24

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:

  1. Login("markbuffalo", "$2a$08$BOHyNdXAVkWOUgPG/hvsjew7ZpngqJIgueY6m76xd4y3UllXUZLBy");
  2. 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.

    
respondido por el Mark Buffalo 13.04.2016 - 19:16
fuente
3

A tu primera pregunta:

Depende de la aplicación. En la mayoría de los casos, la contraseña se envía al servidor en texto sin cifrar (y esto no es seguro si la aplicación utiliza un protocolo no cifrado, como HTTP). El servidor, sin embargo, puede almacenar un valor hash en la base de datos. Si lo hace, la aplicación calcula el valor hash de la contraseña de texto sin cifrar recibida del usuario y la compara con el valor almacenado en la base de datos.

A tu segunda pregunta:

El servidor espera una entrada de contraseña: X . El atacante de alguna manera encuentra h(X) . Luego, si ingresara este valor de hash para autenticarse, la función hash se ejecutaría una vez más contra h(x) , por lo que no podría ingresar ya que h(x) no coincide con h(h(x)) .

    
respondido por el Rápli András 13.04.2016 - 18:35
fuente
1

Como han señalado otros, la forma habitual de que esto funcione es que el cliente envíe la contraseña de texto claro, pero a través de un canal seguro (que utiliza un cifrado reversible , no hash ) y esa contraseña luego se aplasta en el lado del servidor con el mismo salt que el hash almacenado.

       Client      <----- Secure link ----->     Server
Cleartext password     Encrypted password    Hashed password
  1. El cliente tiene la contraseña de cleartext.
  2. El cliente cifra la contraseña (a través de TLS)
  3. El servidor recibe una contraseña cifrada, la descifra (a través de TLS)
  4. El servidor hashea la contraseña con la misma sal que la almacenada en la base de datos para este usuario
  5. El servidor compara el hash computado con el hash almacenado.

Protección:

  • contra escuchas ilegales (debido al uso de un canal seguro)
  • contra los ataques MITM (si la sesión TLS se configura correctamente, los certificados se verifican correctamente, etc.)
  • contra el robo de la base de datos de contraseñas

Ahora el problema es cuando tiene que enviar una contraseña a través de un canal que no proporciona cifrado , como podría ser el caso del protocolo de bajo nivel (por ejemplo, PPP o 802.1X). Las opciones tradicionales (para PPP) fueron:

  • PAP : envíe la contraseña en texto sin cifrar, que luego se puede incluir en el servidor para compararlo con la base de datos de contraseña hash

  • CHAP : use un protocolo de desafío-respuesta y envíe una versión con hash de la contraseña (combinada con el desafío y una identificación a través del enlace, pero esto requería que el servidor almacenara el texto simple de las contraseñas

Así que el primero protege contra el robo de la base de datos de contraseñas, pero no contra las escuchas ilegales, mientras que la situación se invierte para el segundo.

Dejando a un lado los protocolos EAP que realmente configuran un túnel TLS (PEAP, EAP-TTLS, EAP-TLS ...) para asegurar el intercambio de contraseñas, hay un protocolo alternativo que permite enviar un "hash" no reversible de la contraseña a un servidor, que también almacena un "hash" de la contraseña: SRP , y más generalmente "aumentada PAKE ".

    
respondido por el jcaron 14.04.2016 - 18:35
fuente
0

Un ataque basado simplemente en el reenvío de datos capturados (por ejemplo, una contraseña que fue pirateada por el cliente) sin necesidad de descifrar los datos se conoce como un ataque de "repetición". La mitigación estándar para este ataque es incluir lo que se conoce como "nonce" en los datos hash, esto podría ser un número aleatorio proporcionado por el servidor, o una marca de tiempo de resolución razonablemente alta generada por el cliente. El servidor luego verificará que el nonce sea válido o dentro de algún rango aceptable, y si es incorrecto o demasiado antiguo rechazará la solicitud. La discusión detallada se puede encontrar aquí ¿Cuál es el uso de un cliente? ¿nonce?

    
respondido por el Ken 14.04.2016 - 20:43
fuente

Lea otras preguntas en las etiquetas