Ayuda para revisar el algoritmo 2FA

0

Primero que nada, lo sé, no reinventes la rueda ... Pero hay una buena razón para esto.

Así que he estado implementando un algoritmo genérico de validación / generación de código de autenticación de 2 factores para reutilizarlo en múltiples aplicaciones y también dejarlo sin estado (el algoritmo no necesita almacenar nada en la base de datos, y no lo hace No requiere ningún dato de usuario en absoluto.

La aplicación que usa el código es responsable de establecer una carga útil y validarla dentro del proceso genérico de 2 fa.

Así es como funcionaría ...

1: la aplicación solicita un nuevo código 2FA que pasa una carga útil:

1.1 - carga útil: datos arbitrarios, como un ID de usuario y un ID de aplicación.

1.2: se crea un código aleatorio de 7 dígitos (utilizando bibliotecas aleatorias criptográficas seguras)

1.3: se selecciona un tiempo de caducidad, es decir, 3 minutos desde la hora actual, expresado como tiempo de época en segundos.

1.4 - datos: (caducidad, carga útil, código)

1.5: los datos se cifran utilizando el CTR de AES con un IV de 128 bits generado aleatoriamente y una clave secreta

1.6: tanto los datos encriptados como los IV se digieren a través de un HMAC que usa otra clave secreta para firmar estos dos valores.

1.7 - token final: 'datos cifrados en base64: IV: firma'

1.8: el token se devuelve a la IU del usuario (como una aplicación móvil o un usuario web de inicio de sesión)

1.9: el código se envía a través de SMS o correo electrónico

2: la aplicación envía el token original y el código proporcionado por el usuario al backend

2.1: el token se decodifica y la firma se valida

2.2: el token se descifra, se comprueba la caducidad y el código de usuario se compara con el código del token

2.3: la carga útil se devuelve a la aplicación, que realiza una validación adicional, como recuperar un usuario desde la identificación de usuario en la carga útil, etc. ...

¿Está roto? Podría preguntarse por qué no solo almacenar el código de 7 dígitos en la base de datos, sino que la idea es hacer que este sea completamente sin estado y genérico.

También tenga en cuenta: el punto final para la generación / validación de tokens se debe limitar de forma que no se pueda forzar con fuerza bruta.

    
pregunta user1777914 05.07.2018 - 19:38
fuente

2 respuestas

1

Después de pensarlo durante 15 minutos, y suponiendo que se haya implementado correctamente y las aplicaciones que lo usan lo usen correctamente, el único problema menor que se me ocurre es el de un idioma:

  

1.8: el token se devuelve a la IU del usuario (como una aplicación móvil o un sitio web de inicio de sesión)

La interfaz de usuario implica que se presenta al usuario. El usuario no necesita ver el token, solo debe devolverse al cliente del usuario, que lo envía sin que el usuario tenga que verlo. Esto es, por supuesto, un problema muy menor, ya que no hace ningún daño al usuario para que lo vea, simplemente no es realmente necesario.

Por supuesto, probablemente querrás a alguien mejor que yo que lo piense por más de 15 minutos.

Personalmente, espero que una vez que un porcentaje suficientemente importante de personas esté usando 2FA (y en suficientes lugares sea compatible con 2FA), los phishers comenzarán a usar proxies como Evilginx , a las que las soluciones OTP son vulnerables. Por lo que sé, el único método 2FA que evita esto ahora es U2F, que requiere almacenar una clave pública para cada usuario.

No creo que sea incluso posible evitar este tipo de phishing sin almacenar una clave pública, un secreto o algo similar por usuario. Si estuviera implementando 2FA, trataría de hacerlo compatible con U2F, o al menos intentaré diseñarlo para que se pueda agregar fácilmente U2F o un método futuro, si lo desea.

También tenga en cuenta que ni SMS ni correo electrónico tienen garantías sólidas de que no serán interceptados. Al menos con TOPT o HOTP, podría usar algo como Google Authenticator que, aunque sigue siendo vulnerable contra un proxy malicioso, al menos no tiene que enviar un código que pueda ser interceptado.

    
respondido por el AndrolGenhald 05.07.2018 - 23:44
fuente
0

Parece que "No quiero caminar un kilómetro, así que caminaré cien kilómetros en lugar" . Guardar siete números en una base de datos, un archivo plano o cualquier otra cosa es mucho más fácil y genérico también. Su solución no es sin estado, ya que el estado se envía al cliente.

Definitivamente no usaría su sistema, está lleno de partes móviles. Si va a enviar un token al usuario por correo electrónico o SMS, simplemente guárdelo y compare más tarde. Una pequeña base de datos sqlite es suficiente, y hay bibliotecas para usarla en casi todos los idiomas. Tendrías una base de datos como esta:

[userid | token   | expiration         ]
|192    | 1234567 | 2018-07:15 10:11:12|
|723    | 7482912 | 2018-07:15 15:24:33|
----------------------------------------

Para evitar que la base de datos se haga demasiado grande, puede ejecutar un trabajo cada hora aproximadamente para eliminar los tokens caducados.

Puede simplificar un poco el sistema y deshacerse del trabajo de limpieza utilizando un TOTP . Crear una base de datos con el ID de usuario y la clave. Cuando el usuario quiere autenticarse, usted solicita el token. El usuario abrirá Google Authenticator, Authy , 1Password , Enpass o cualquier cliente TOTP que use. Cuando el usuario envía el token, usted calcula y valida el token. También hay muchas bibliotecas TOTP disponibles para casi todos los idiomas.

Para utilizar el segundo enfoque, solo agregará una base de datos sqlite muy pequeña y una biblioteca a su aplicación. Creo que la sobrecarga es muy pequeña y simplifica mucho el proceso.

    
respondido por el ThoriumBR 05.07.2018 - 22:30
fuente

Lea otras preguntas en las etiquetas