Encriptación del lado del cliente de los datos del usuario con la contraseña del usuario

2

He reducido un esquema que permitiría a mi aplicación cifrar el lado del cliente de datos del usuario y transmitir esos datos al servidor, sin posibilidad alguna de que nuestro servidor pueda descifrar los datos.

Quiero asegurarme de que no haya fallas obvias en este esquema.

Método

Nota: cada paso a continuación ocurre en el lado del cliente.

Precursor:

  1. Al iniciar sesión / registrarse, genere la clave global gk = SHA256(user_password) y almacene gk en una cookie localStorage. (El motivo de esto es no almacenar la contraseña del usuario claramente).

Encriptación:

  1. Para cada archivo, genere una clave aleatoria fk .
  2. Cifre el archivo con fk .
  3. Cifre fk con gk para obtener fk '.
  4. Transmitir el archivo cifrado y fk ' al servidor para su almacenamiento.

Descifrado:

  1. Recibir el archivo cifrado y fk ' del servidor.
  2. Descifre fk ' usando gk para obtener fk .
  3. Descifre el archivo usando fk .

Cuando el usuario cambia la contraseña:

  1. Para cada archivo, descifre fk ' usando gk actual para obtener fk .
  2. Genere un nuevo gk con una nueva contraseña.
  3. Cifre fk con el nuevo gk para obtener fk '.
  4. Transmitir el nuevo archivo fk ' al servidor para su almacenamiento.

Cuando el usuario olvida la contraseña:

  1. Fuera de suerte. (A menos que?)

¿Qué fallas existen en este procedimiento?

Actualizar

Una falla es que si el usuario autentica el inicio de sesión con una contraseña, técnicamente, puedo calcular y almacenar fácilmente gk en el servidor, comprometiendo así la promesa de cifrado del lado del cliente.

Una solución a esto:

  1. Genere pw = SHA256(SHA256(user_password)) y envíe esto al servidor como la contraseña del usuario. El servidor recibe esta contraseña y la cifra nuevamente antes de almacenarla.

Por lo que respecta al servidor, solo está recibiendo una contraseña normal. Pero de esta manera, gk no se puede calcular del lado del servidor.

¿Fallos?

    
pregunta Snowman 16.11.2016 - 20:54
fuente

2 respuestas

5

La falla más grande en este esquema es que depende del código javascript que será transmitido al cliente por el (a) servidor.

Entonces, ¿qué es mantener al servidor (oa un hombre en el medio) para enviar el javascript modificado del cliente que elude todas las medidas de seguridad? ¿Cómo lo sabría el cliente o, en realidad, el usuario? Todo el código que escriba para verificar huellas dactilares, sumas de comprobación, firmas digitales, etc. también puede ser evitado.

Un problema relacionado es otro código javascript malicioso que se ejecuta en su navegador y que no se puede aislar de manera confiable de su código javascript relacionado con la seguridad.

Esto es imposible de arreglar. El Javascript del navegador no es actualmente una plataforma segura y toda la criptografía del lado del cliente del navegador sufre este agujero de seguridad enorme que no se puede cerrar.

Resumen de la discusión en los comentarios sobre la pregunta actualizada

Calcular pw = sha256 (sha256 (user_password)) me parece una mala idea por varias razones.

  1. AgentMe ya mencionó el primero: no uses hash simple Funciones como sha-lo que sea para hash de contraseñas. Estas funciones hash fueron diseñadas para ser implementadas eficientemente en hardware y son mucho, mucho demasiado rapido; Para las contraseñas de hash, quieres funciones de hash lentas. Ver AgentMe respuesta.
  2. Con este esquema, pw puede calcularse si conoces gk (que es solo sha256 (user_password)). Entonces, cuando alguien roba su almacenamiento local, le da acceso tanto a la clave de cifrado principal como al token de autenticación / autorización que necesita para descargar los archivos cifrados. Sería mejor mantener los dos secretos independientes uno del otro, de modo que si uno está comprometido por un tercero, no es suficiente calcular el otro y romper la confidencialidad de los datos cifrados.
  3. Finalmente, no estás agregando tu contraseña de usuario con este esquema. Esto significa que las contraseñas idénticas en toda su base de usuarios producirán valores hash idénticos (y ya hay tablas arco iris grandes para sha-hashes sin sal que contienen los pocos millones de contraseñas más comunes).

Usted sugiere una alternativa, por ejemplo, gk = sha256 (contraseña_usuario) y pw = sha128 (contraseña_usuario). Si bien esto resuelve el punto 2, no aborda 1 y 3. Además, no lo recomendaría porque podría imaginar que proporciona información adicional innecesariamente a un atacante (la misma contraseña con dos valores hash diferentes), aunque No sé cómo explotarlo.

Sugerí usar gk = hmac (user_password, n) y pw = hmac (user_password, m), donde m y n son conocidos, pero diferentes para cada usuario. La forma en que llegue a m y n es irrelevante, siempre y cuando sean aleatorios y suficientemente grandes para que sean únicos en su base de usuarios con una alta probabilidad. Puede crearlos en el cliente y enviarlos para su almacenamiento en el servidor, indexados por el nombre de usuario para que puedan recuperarse en otros clientes. O puede hacer que el servidor los genere cuando el usuario crea una cuenta por primera vez. Los valores no necesitan mantenerse seguros; No valen nada sin la contraseña de usuario. Una mejora mejorada sería usar gk = hmac (bcrypt (user_password), n) y pw = hmac (bcrypt (user_password), m) para hacer que los ataques de fuerza bruta sean más difíciles.

Ahora, no estoy convencido de que esta sugerencia sea una buena idea, ya que hmac está diseñada para la autenticación de mensajes, no para crear tokens de autenticación o claves de cifrado, por lo que tomaría esa sugerencia con un poco de sal. Pero parece resolver los tres puntos que planteo, así que parece una solución mejor que encadenar la misma función hash o usar dos funciones hash diferentes en la contraseña.

    
respondido por el Pascal 16.11.2016 - 22:46
fuente
1
  1. gk debe almacenarse en localStorage / IndexedDB y no en una cookie, ¡porque las cookies se envían al servidor!
  2. Debería usar un algoritmo de derivación de clave / hashing de contraseña más fuerte que SHA256, que es más resistente a la fuerza bruta.
  3. ¿Cómo se autentica el usuario en el servidor? Probablemente no desee permitir que cualquier usuario solicite o actualice los archivos fk' cifrados para cualquier otro usuario. Querrá que los usuarios se autentiquen de una manera que no sea el envío de su contraseña de texto sin formato. Podría pedirles que envíen el valor gk puesto a través de la función de derivación de claves por segunda vez.
  4. Consulte enlace . Usted (o alguien que lo coacciona, o alguien que lo ha pirateado) puede obtener datos de usuario cambiando el javascript que su servidor proporciona para que envíe los valores de gk de los usuarios al servidor o, de lo contrario, los filtre. Esto podría mitigarse con un buen uso de los trabajadores de servicios que tienen un código revisado abiertamente, pero no estoy seguro de que alguien lo haya hecho satisfactoriamente todavía.
respondido por el Macil 16.11.2016 - 22:31
fuente

Lea otras preguntas en las etiquetas