¿Cómo enviar solo contraseñas con hash sin almacenar las contraseñas en texto sin formato en el servidor?

1

En un sistema de autenticación basado en web, hago lo siguiente:

  1. Cliente: solicite al servidor un "nonce".
  2. Cliente: genere un "cnonce".
  3. Cliente: hash (nonce + cnonce + contraseña)
  4. Cliente: envíe cnonce y el hash desde el punto 3 al servidor.

  5. Servidor: hash (nonce + cnonce + password)

  6. Servidor: Compara los hashes.

Esto requeriría que guarde las contraseñas en texto sin formato / cifrado ya que el servidor necesita una "contraseña" para calcular el hash con el que comparar.

Por supuesto, no quiero hacer esto y, por lo tanto, hash todas las contraseñas guardadas en el servidor con hash (contraseña, salt). Pero ahora no puedo comparar con el hash que me envía el cliente ya que no tengo el componente de contraseña.

Una forma de resolver esto sería proporcionarle al cliente el usuario único salt para que el cliente pueda calcular el hash (nonce + cnonce + hash (contraseña, salt)) y enviarlo al servidor, permitiendo que el servidor compare Los hashes. Pero de acuerdo con ¿Cómo almacenar sal? la sal nunca debe compartirse.

La razón por la que uso nonce en una conexión HTTPS se describe en: ¿Debo copiar la contraseña antes de enviarla al servidor?

¿Entonces mi pregunta es cómo salir de este bucle infinito de "no hacer"?

    
pregunta Gurgy 06.01.2017 - 16:21
fuente

3 respuestas

2

Para resumir los comentarios:

No entiendo completamente la respuesta de stackoverflow a la que te refieres. En su explicación, envía un nonce desde el servidor al cliente a través de HTTPS que se considera roto en este ataque. Para ello el atacante obtiene el nonce. Se genera un cnonce y se anula la falta de acceso y la contraseña.

El cnonce y el hash se envían a través de la conexión HTTPS (presumiblemente insegura). El atacante ahora tiene el nonce, cnonce y hash. Puede intentar revertir el hash para obtener la contraseña (bruteforce). Pero eso ni siquiera es necesario ya que el servidor está dispuesto a aceptar el hash y otorgar acceso. El ataque simplemente reenvía el hash. Como @Matthew declaró, acabas de crear un sustituto de contraseña.

Podría invalidar el nonce del servidor después de una autenticación, de modo que si el hash se reenvía se rechazará. Esto parece una mejora de seguridad, ya que el atacante solo podría tener éxito invirtiendo el hash, que es muy difícil con contraseñas complejas y largas.

¿El esfuerzo supera el beneficio? Creo que sí, HTTPS se considera seguro si está configurado correctamente. Todo el Internet depende de HTTPS para asegurar la autenticación, por lo que, a menos que su aplicación sea muy confidencial, debe confiar en ella.

¡Buena suerte en la tarea!

    
respondido por el Silver 06.01.2017 - 17:00
fuente
0

El objetivo de la sal es que diferentes cuentas tendrán diferentes contraseñas con hash (por lo que me refiero al resultado final que almacena en su db, después de todas las transformaciones).

Por lo tanto, no es un problema que un atacante aprenda la sal utilizada para un usuario determinado. Podría comenzar a calcular posibles contraseñas con hash, pero necesitaría una tabla arco iris diferente para el usuario, por lo que no sería útil realizar tales cálculos antes de robar su base de datos.

El problema de compartir la sal con el cliente es que puede estar perdiendo los usuarios que existen en su base de datos, ya que los usuarios existentes siempre devolverán la misma sal (puede ofuscarla devolviendo una sal derivada del nombre de usuario dado para usuarios que realmente no existen).

También tenga en cuenta que, aunque no especifique qué es exactamente la operación + en sus hashes anteriores, debe reemplazar con hmac los pasos para tomar un hash de los valores combinados.

Por ejemplo, suponiendo que + fuera el operador de concatenación, un actor malintencionado que interceptó una solicitud de inicio de sesión con nonce = 123456789 y cnonce = 987654321, podría suplantar una solicitud de inicio de sesión donde el servidor proporcionó un nonce = 12345 (es decir, hay una mayor probabilidad de obtener un nombre válido que solo obtenga exactamente el mismo).

También puede encontrar interesante el Protocolo de contraseña remota segura ( RFC 5054 ). Aunque ambas partes trabajan con contraseñas de texto simple, también puede adaptarlas a los hash salados calculados en ambos lados (su "contraseña" es la salida de la operación salt).

Finalmente, debe comprender que en estos esquemas, el hash con sal es equivalente a texto simple, ya que es suficiente para iniciar sesión. Puede almacenar esa contraseña con sal encriptada¹ con una contraseña específica de la aplicación (tendría un rol similar al un pimiento ), pero no obstante, sus propiedades en caso de compromiso serían un poco diferentes que en el enfoque habitual. Si alguien robó su base de datos (por ejemplo, de un volcado de SQL en una copia de seguridad desprotegida), esta pimienta -si no es robada con la base de datos- sería lo único en el camino del atacante que le impide hacerse pasar por cualquier usuario.

¹ sí, debe ser reversible para que su protocolo funcione

    
respondido por el Ángel 06.01.2017 - 17:31
fuente
0

El servidor ciertamente necesita almacenar un verificador para cada entrada de contraseña. Nuestros verificadores serán (user_salt, server_salt, server_hash) triples, donde:

  • user_salt y server_salt son matrices de 16 bytes aleatorias.
  • server_hash = keyedhash(server_salt, pwhash(user_salt, password)) , donde:
    • pwhash denota una función de hashing de contraseña "lenta" como PBKDF2, bcrypt, scrypt o Argon2;
    • keyedhash denota una función de hash con clave como HMAC-SHA2.

Ahora podemos usar un protocolo de autenticación como este:

  1. Cliente: envía username al servidor;
  2. Servidor: responde con el correspondiente user_salt ;
  3. Cliente: calcula client_hash = pwhash(user_salt, password) ;
  4. Cliente: envía client_hash al servidor;
  5. Servidor: calcula server_hash = keyedhash(server_salt, client_hash) ;
  6. Compara server_hash con el valor almacenado en la entrada de la contraseña del usuario.

El protocolo de inscripción / cambio de contraseña es similar:

  1. Cliente: se autentica con el servidor;
  2. Cliente: envía una solicitud de cambio de contraseña;
  3. Servidor: responde con un new_client_salt aleatorio;
  4. Cliente: calcula new_client_hash = pwhash(new_client_salt, new_password) ;
  5. Cliente: envía new_client_hash ;
  6. Servidor: selecciona un new_server_salt aleatorio;
  7. Servidor: calcula new_server_hash = keyedhash(new_server_salt, new_client_hash) ;
  8. Servidor: almacena la entrada de la nueva contraseña de (new_client_salt, new_server_salt, new_server_hash) como username .

Ambos protocolos deben ejecutarse a través de un canal autenticado y confidencial (por ejemplo, una conexión SSL). Un intruso que vea client_hash podría hacerse pasar por el usuario.

Una de las ventajas de un protocolo como este es que, además de no enviar nunca la contraseña por el canal, calcula la función de hashing de contraseña lenta en el lado del cliente, lo que significa que puede aumentar el factor de trabajo de la función para hacer Los ataques de craqueo de contraseñas son más difíciles.

Vea también estos enlaces para propuestas similares:

respondido por el Luis Casillas 06.01.2017 - 20:33
fuente

Lea otras preguntas en las etiquetas