Autenticar usuario sin saber su contraseña

1

Estoy trabajando en un proyecto donde cada usuario tendrá un par de claves RSA público / privado. Los usuarios podrán enviarse mensajes cifrados entre sí utilizando la clave pública de cada usuario de destino para que solo los usuarios de destino puedan leer el mensaje (similar a PHP openssl_seal ). Como queremos que el usuario pueda usar cualquier dispositivo para leer o enviar un mensaje, el par de claves se almacenará en un servidor API y la clave privada se cifrará con la contraseña del usuario .

Cuando un usuario inicia sesión desde un nuevo dispositivo, utilizará su contraseña para descifrar la clave privada. El problema es que, idealmente, el servidor API nunca debería poder descifrar la clave privada del usuario, incluso para autenticar al usuario . Originalmente, solo iba a enviar al cliente la clave privada cifrada y permitir que el cliente la descifre. Si el cliente puede descifrarlo, debe tener la contraseña correcta, pero esto sería vulnerable a los ataques de diccionario sin conexión. Para evitarlo, debo autenticar al usuario antes y les doy la clave privada cifrada.

Podría hacer que el cliente envíe la contraseña al servidor y permita que el servidor intente descifrar la clave utilizando la contraseña o incluso simplemente validar la contraseña contra un hash, pero entonces el servidor tendrá la contraseña temporalmente y podrá descifrarla. La clave privada del usuario. Está bien, pero prefiero encontrar una manera de autenticar al usuario sin que el servidor sepa su contraseña.

En mi caso, el cliente será un servidor web PHP o una aplicación de escritorio o móvil nativa, no un navegador, por lo que tengo acceso a una amplia gama de métodos criptográficos. El único cliente autorizado para realizar la llamada al servidor API para crear una cuenta será el servidor web PHP, y actualmente estoy planeando que cree el par de claves pública / privada y encripte la clave privada con la contraseña del usuario. Luego, enviará esa información al servidor API (también ejecutando PHP) para crear la cuenta. El servidor API almacenará la clave privada cifrada, la clave pública, la información sobre el usuario y cualquier mensaje cifrado, pero no podrá descifrar ninguna de ellas.

No estoy tratando de protegerme contra un ataque MITM aquí. Todas las llamadas a la API se realizarán a través de HTTPS. Mi objetivo es construir la API de tal manera que incluso si el gobierno chino pudiera obtener acceso al servidor de la API, aún no pudieran leer ninguno de los mensajes. El servidor web puede tener la clave privada temporalmente, pero no el servidor API.

¿Cómo puedo permitir que el servidor API autentique al usuario sin ser vulnerable a un ataque de fuerza bruta sin conexión y sin que el servidor API necesite la contraseña del usuario?

No dude en decirme que estoy haciendo algo totalmente incorrecto y sugerir algo completamente diferente.

    
pregunta Joshua Dwire 04.12.2013 - 17:21
fuente

5 respuestas

3

Hágalo de la manera que lo hace MEGA: realice todo el descifrado de cifrado dentro de su navegador usando JavaScript. Solo permita que los archivos cifrados se envíen al servidor (a menos que, por supuesto, las claves públicas).

No es necesario enviar la clave privada en ningún momento al servidor (porque todo se está haciendo desde el navegador). Una pequeña advertencia, sin embargo, si su usuario pierde una contraseña o si un archivo cifrado se corrompe, entonces básicamente está atornillado y todos los mensajes serán inútiles ya que ya no tiene la clave.

Para autenticar al usuario, puedes usar algo como abrir OpenID. El usuario todavía tendría que proporcionar una contraseña para descifrar su clave privada, pero en ningún momento la contraseña descifrada se envía al servidor (todo permanece dentro del navegador).

    
respondido por el Lucas Kauffman 04.12.2013 - 17:41
fuente
3

PBKDF2: esto le permitirá validar que el usuario tiene la contraseña, sin tener que enviar la contraseña. En el lado del servidor, no guarda la contraseña, sino que guarda un hash de la contraseña.

    
respondido por el Jeffrey Bloom 05.12.2013 - 16:30
fuente
2

Este diseño adolece de una "promesa de no subir al pico" y es muy similar a los problemas de seguridad LavaBit tenía , MEGA también tiene este problema.

Para verificar que un usuario tiene las credenciales de autenticación correctas, necesita un sistema centralizado para verificar estas credenciales. Este sistema centralizado puede ser modificado por un atacante para registrar las credenciales de autenticación. .

MITM es el problema y este ataque es utilizado por los gobiernos. Una aplicación que registra todas las contraseñas tiene el mismo efecto y podría ser introducida por un atacante.

    
respondido por el rook 04.12.2013 - 18:59
fuente
2

¿Por qué no solo usar un método de autenticación basado en token existente como Kerberos y construir a partir de él?

Por lo tanto, el usuario se autentica normalmente y recibe un token kerberos. Luego, vas al servidor de API y dices "¡Oye, tengo este token!" El servidor API lo verifica y envía una copia de los datos cifrados al usuario, ¿quién puede descifrar las claves en su máquina?

Parece bastante simple.

    
respondido por el Desthro 09.10.2014 - 17:47
fuente
1

Está diciendo que la clave privada no se puede descifrar del lado del servidor para la autenticación (porque entonces el servidor necesitaría la contraseña), y tampoco se puede enviar a nadie que la solicite, y luego se descifra del lado del cliente (porque entonces el la clave privada sería vulnerable a un ataque de fuerza bruta sin conexión).

Básicamente, lo que queda es diseñar un mecanismo de contraseña completamente separado y almacenar alguna forma de la contraseña (por supuesto, hash / salted, etc.) en el servidor independientemente de la clave privada. El gran inconveniente es que esto duplica la superficie de ataque de su clave privada: un atacante puede acceder a la clave privada ya sea por descifrarla directamente o al ingresar a dicha base de datos de contraseñas.

Hay un enfoque completamente diferente. En lugar de tener un par de claves por usuario, tenga un par de claves por dispositivo. Creo que Apple lo usa para el iCloud. Cuando un usuario conecta un nuevo dispositivo, se genera un par de claves completamente nuevo. Eso evita la necesidad de que la clave privada salga del dispositivo. La parte difícil, y la que no entiendo completamente, es cómo los pares de teclas de varios dispositivos interactúan entre sí.

Actualizar:

Apple tiene información sobre cómo funciona esto. Mira la sección para el llavero de iCloud. No es un detalle técnico, pero es suficiente para aventurar un par de conjeturas adicionales.

Con este esquema, no utilizaría la contraseña para cifrar ninguna clave (lo cual es un gran beneficio porque las contraseñas son siempre la parte más débil del cifrado).

Aquí es cómo podría aplicarse a su situación:

  • Cada dispositivo en su servicio obtiene su propio par de claves cuando el usuario lo registra. Esto sucedería de manera transparente; la clave privada nunca llegará a su servidor (ni encriptada ni encriptada).

  • Cada cuenta de usuario tiene una clave de cifrado principal (clave simétrica, no pública) que realmente se usa para cifrar el contenido. Apple aparentemente utiliza AES128.

En el registro inicial para el primer dispositivo:

  • El dispositivo genera un par de claves y envía la clave pública al servidor.

  • El servidor genera la clave maestra, la cifra mediante la clave pública y almacena la clave maestra cifrada en el registro del dispositivo de su base de datos. Esta es la única vez que el servidor tiene la clave maestra sin cifrar.

Al iniciar sesión en su servicio:

  • El usuario inicia sesión en su servicio utilizando el nombre de usuario / contraseña.

  • El dispositivo recupera la clave de cifrado maestra que se cifró con su propia clave pública.

  • El dispositivo descifra localmente la clave de cifrado principal y la usa para acceder al contenido de su servidor.

Al agregar un nuevo dispositivo, el usuario necesita un dispositivo ya registrado (dispositivo A) y, por supuesto, el nuevo dispositivo (dispositivo B)

  • El usuario usa el dispositivo B para registrarse con su servicio. Esto generará otro par de claves. Es posible que necesite un nombre de usuario y una contraseña para hacerlo.

  • el dispositivo B envía una clave pública al servidor.

  • El usuario inicia sesión utilizando el dispositivo A y "autoriza" el dispositivo B.

  • el dispositivo A recupera la clave maestra con la clave pública del dispositivo A.

  • el dispositivo A recupera la clave pública del dispositivo B.

  • dispositivo A descifra la clave maestra usando su propia clave privada y luego la vuelve a cifrar usando la clave pública del dispositivo B.

  • el dispositivo A carga la clave maestra cifrada con la clave pública del dispositivo B al servidor.

En este punto, el servidor tiene dos copias de la misma clave maestra simétrica: una cifrada con la clave pública del dispositivo A, una con la clave pública del dispositivo B.

El dispositivo A y el dispositivo B ahora pueden acceder al contenido con la misma clave maestra.

Aparentemente, Apple también permite almacenar la clave de cifrado maestra sin cifrar en su servidor para permitir la recuperación de la clave si pierde todos sus dispositivos. Esto obviamente socava su objetivo declarado.

Obviamente, este enfoque es vulnerable a al menos dos ataques:

  • Una aplicación cliente maliciosa puede filtrar la clave maestra sin cifrar.
  • Un servidor comprometido puede almacenar la clave maestra a medida que se genera. Puede evitarlo generando la clave maestra del lado del cliente en el cliente inicial.

Una captura más: este método puede estar sujeto a una patente.

    
respondido por el Kevin Keane 06.04.2015 - 01:02
fuente

Lea otras preguntas en las etiquetas