¿Cómo cifrar los datos en el frontend / backend con una clave que no se almacena en ningún lugar y solo la conoce el propietario?

1

He leído un montón de respuestas y tutoriales sobre cómo la criptografía del lado del cliente no es una buena idea debido a muchas razones enumeradas principalmente en Criptografía Javascript considerada dañina . Algunos hechos

  1. La aplicación utilizará HTTPS
  2. Habrá validación del lado del servidor y del cliente
  3. No hay un vínculo entre la contraseña del usuario y el siguiente escenario
  4. El lado del servidor es un servicio web RESTful (sin sesión alguna)
  5. El backend emite JWT a los usuarios
  6. El backend puede permitir tanto al usuario / contraseña como a oauth (es decir, fb, twitter, etc.)

¿Qué deseo cifrar en el lado del cliente?

El usuario ingresará información personal (es decir, nombre, dirección, número de teléfono) a través de una aplicación de interfaz (es decir, Vue.js, Angular, React, etc.)

¿Cómo me imagino que esto va a funcionar?

El usuario selecciona campos (es decir, partes y partes de información personal), y luego hace clic en cifrar. El usuario proporcionará una clave de cifrado. La interfaz utilizará un poco de js crypto library y cifrará la información, la reemplazará en el DOM e informará al usuario para hacer una copia de seguridad de la clave de cifrado.

¿Cómo comunico esta información al servidor?

El frontend realizará una solicitud HTTP PUT o POST con la información personal (ya sea simple / texto o gibberish) al servidor. El servidor no se preocupa por los datos entrantes (es decir, excepto por SQL u otras formas de inyecciones) y los almacena en la base de datos de inmediato. Esta solicitud no contendrá el encryption key , pero podría contener un indicador / s para especificar qué campos se cifraron.

¿Cómo descifrar?

Cuando el usuario solicita la información, el backend devuelve todo lo que hay en el servidor tal como está. La información si está encriptada se mostrará como gibberish al usuario. Usando indicadores, el sistema les dará la opción decrypt y al hacer clic en ellos les pedirá que ingresen encryption key y realice el descifrado localmente.

¿Último propósito?

En primer lugar, se hará todo lo posible para asegurarnos de que el servidor y la base de datos y todo estén a prueba de balas, pero, si por alguna razón el servidor es pirateado, el pirata informático terminará con mucha información relacionada con el engaño. informacion personal.

La pregunta definitiva

Al leer a través de Internet, la criptografía en Javascript está totalmente desaconsejada, por lo tanto, mis preguntas

  1. Teniendo en cuenta el escenario y el requisito anterior, ¿cuáles son los riesgos que imponen la implementación anterior?
  2. ¿Hay algún enfoque que recomiende, donde solo el usuario tenga el control de la clave, no se almacene en ningún lugar?
  3. Si tuviera que cifrar esta información en el backend, ¿cómo puedo comunicar el encrypt key de forma segura al usuario? ¿Tal vez encripte la información con la clave xyz y luego proporcione un enlace seguro al usuario para hacer clic y ver la clave de encriptación xyz , ...?
  4. ¿Qué otras sugerencias existen para el cifrado de front-end, basado en back-end?

Me gustaría darle la confianza al usuario de que solo ellos saben cómo descifrar la clave. ¿Cómo puedo lograr eso de una manera más eficiente? ¿Sin tener que almacenar y gestionar la clave de cifrado?

Actualización 17 de julio de 2018

Sobre la base de la respuesta aceptada, escribí una publicación mediana sobre cómo implementé la solución aquí es el enlace enlace

    
pregunta Raf 14.06.2018 - 23:00
fuente

1 respuesta

3

Tras el registro inicial del usuario, genere una clave de cifrado segura utilizando un generador de números pseudoaleatorios criptográficamente seguro; esta clave servirá como la clave de cifrado de datos (DEK) para cifrar los datos del usuario. Pero no desea almacenar el DEK en ningún lugar, al menos en su forma de texto simple. Desea derivar una clave de cifrado a partir de la contraseña del usuario, utilizando una función de derivación de claves como PBKDF2. Use la clave que derivó de la contraseña del usuario (la clave de cifrado de clave o KEK) para cifrar el DEK. Luego, puede guardar de forma segura el texto cifrado de ese DEK en la base de datos.

Cada vez que el usuario inicie sesión, no solo debe autenticarlos, sino que también debe obtener el KEK de nuevo a partir de su contraseña, y luego usar esa clave derivada para descifrar el texto cifrado del DEK. Almacene el DEK en la sesión en el servidor, no en el cliente. Ahora estás en el negocio; puede usar el DEK para descifrar información en el lado del servidor mientras la sesión esté activa, pero no después de que la sesión caduque. Esto tiene la ventaja de que el usuario no tiene que mirar fijamente a algún texto cifrado del libro. En su lugar, puede tener un elemento DOM de contenedor de marcador de posición que dice "encriptado" o algo así, y tal vez escuchar los clics en ese elemento, que luego invocan una llamada a un punto final de API, que toma el texto cifrado de la base de datos, lo descifra en el servidor con el DEK que guardó en la sesión, luego lo devuelve al cliente como texto sin formato en ese mismo momento, donde puede inyectarlo en la interfaz de usuario para que lo vea el usuario. No es necesario almacenar datos confidenciales en el cliente, ni es necesario realizar ninguna operación criptográfica en el cliente. Este enfoque también tiene el beneficio adicional de que el DEK puede mantenerse constante a lo largo del tiempo. Si el usuario alguna vez cambia su contraseña, simplemente derive un KEK de la nueva contraseña y vuelva a cifrar el mismo DEK que antes con el nuevo KEK, y almacene el nuevo texto cifrado del DEK en la base de datos como antes.

    
respondido por el vrtjason 14.06.2018 - 23:51
fuente

Lea otras preguntas en las etiquetas