¿Es este esquema de autenticación de contraseña de bricolaje aceptable?

1

Este es principalmente un experimento mental para la comunicación cliente / servidor, y quiero conocer las fallas.

Cuando se crea una cuenta de usuario (con U como nombre de usuario y P como contraseña), genero un salt aleatorio ( S ) y almaceno estos valores en la base de datos (en el lado del servidor) : U , S y H que se calcula como H = hash(U+S+P) .

Al autenticar un usuario:

  1. El cliente primero "intenta una autenticación" enviando U al servidor.
  2. El servidor crea un código de desafío ( R ) para ese usuario y lo almacena en la base de datos, junto con el tiempo en que este desafío vencería ( T ) y envía R y S al cliente .
  3. El cliente calcula su propia versión de H (mediante la combinación de hashing U y S y P juntos; tiene U y P , y recibió S del servidor.)
  4. El cliente luego calcula un nuevo valor G como G = hash(H+R) y envía este G nuevamente al servidor ("solicitud de autenticación" real).
  5. El servidor tiene su propio H junto con R para reconstruir G y autentica al usuario si su G coincide con el valor recibido del cliente y T no ha pasado todavía.
  6. Si la autenticación se realiza correctamente o falla, R se elimina de la base de datos del servidor.

Los defectos que ya conozco son estos:

  • Al crear una cuenta, la contraseña se transmite en texto sin formato. Esto se puede mitigar utilizando un servicio dedicado de creación de cuentas que emplea SSL para crear cuentas.
  • Intentar una autenticación dará como resultado que se asignen algunos recursos en el servidor. Esto se puede mitigar permitiendo solo uno (o un número fijo) de códigos de desafío por usuario.
  • Intentar descubrir nombres de usuario y sales válidos al generar muchos intentos de autenticación; que el servidor puede frustrar al enviar un código aleatorio de sal y desafío incluso cuando el usuario no existe.

Aquí están mis preguntas específicas:

  1. ¿Qué me estoy perdiendo? ¡¿Dónde está el desastre esperando a suceder ?!
  2. ¿Qué puedo hacer para que esto sea más seguro / mejor? Aparte de usar SSL y simplemente enviar contraseñas de texto sin formato (texto sin formato solo desde la perspectiva de mi aplicación).
  3. Estoy pensando en SHA-256 para todos los hashes. ¿Hay algún defecto en la familia SHA-2? ¿Es hash de los valores una vez suficiente para generar H y G ?
  4. Para generar H y G , ¿son mejores otras permutaciones de valores? p.ej. P+U+S , R+H , etc.
  5. ¿Qué ventajas estoy negando a mis usuarios? (Aparte de sus autenticaciones que ahora necesitan dos viajes de ida y vuelta al servidor).

ACTUALIZACIÓN : En última instancia, quiero hacer esto:

Después de una autenticación exitosa, el servidor genera una clave de sesión K como: K = hash(H+F) donde F es una cadena aleatoria. F se envía al usuario y K se retiene en la base de datos. El cliente reconstruye K utilizando el F recibido y encripta todas las comunicaciones con el servidor en adelante con un cifrado simétrico (por ejemplo, AES) con K como clave.

    
pregunta yzt 25.05.2015 - 22:44
fuente

1 respuesta

8

Su problema principal se puede resumir en: ¿dónde está el SSL?

Cualquier observador oculto, observando los intercambios, obtendrá suficiente información para ejecutar un ataque de diccionario sin conexión : el atacante podrá "probar contraseñas" volviendo a calcular los valores de hash relevantes y ver si coinciden. que se observó. Esto está "fuera de línea" porque el atacante puede hacer todo esto en sus propias computadoras, sin interactuar con el cliente o el servidor. El atacante puede hacer todo esto a la velocidad de sus propias máquinas y, gracias al hecho de que las funciones hash habituales se relacionan muy bien con lo que pueden hacer la CPU y la GPU modernas, podrá probar miles de millones de contraseñas por segundo. No hay muchas contraseñas que duren mucho en estas condiciones.

Puedes intentar hacer un Diffie-Hellman anterior para obtener una clave de cifrado compartida, y encripta todo con eso, pero acabas de pasar el problema al de hacer un Man-in-the- Ataque medio : crees que hablas con el servidor, pero realmente estás hablando con el atacante, con quien haces el intercambio de claves DH. El atacante vuelve a la situación anterior y puede observar los hashes que le permiten ejecutar un ataque de diccionario sin conexión.

La solución normal es configurar primero un túnel seguro para el servidor, que al menos garantice al cliente que está hablando con el servidor deseado y con nadie más. Esto se llama SSL (o TLS , que es su nombre "estándar"). Una vez que tenga dicho túnel, puede usar un método de autenticación "mostrar la contraseña" mucho más simple, y el túnel también garantizará que todos los intercambios de datos posteriores se vincularán con esa autenticación (es decir, los atacantes no podrán secuestrar el socket) después de los pasos de autenticación).

SSL asume que el cliente tiene una forma de verificar la identidad del servidor, ese es el punto del certificado del servidor. Si quiere prescindir de ese certificado y lograr una autenticación mutua basada en la contraseña del cliente y el servidor, pero sin revelar nada que permita a los atacantes ejecutar ataques de diccionario sin conexión (incluso los atacantes activos que intentan hacerse pasar por el cliente o el servidor) , entonces necesita uno de estos ingeniosos algoritmos intercambio de claves autenticado por contraseña . Una vez más, utilice SSL, con conjuntos de cifrado SRP . Los únicos protocolos conocidos que tienen éxito en dicha autenticación sin certificado, sin ofrecer ataques de diccionario sin conexión, utilizan algunas matemáticas; no lograrás eso simplemente usando funciones hash.

Independientemente del protocolo de autenticación , todavía necesita un función de hashing de contraseña segura para cualquier cosa que almacene en el lado del servidor, para evitar transformar una intrusión parcial de solo lectura (por ejemplo, a través de alguna inyección de SQL) en una fiesta que rompe la contraseña.

Y, por supuesto, en la criptografía, "hazlo tú mismo" es el camino más rápido hacia el infierno.

    
respondido por el Thomas Pornin 26.05.2015 - 02:45
fuente

Lea otras preguntas en las etiquetas