¿Es una mala idea agregar caracteres aleatorios al ID de usuario y la contraseña?

16

He escuchado a la gente decir una y otra vez que no deberías implementar tu propio algoritmo de seguridad, y me gustaría preguntarte si estoy incumpliendo esta regla.

Estoy creando una aplicación cliente-servidor tradicional con un giro: quiero cifrar todos los datos en el cliente para que incluso un atacante que obtenga un control completo sobre mi servidor no pueda acceder a los datos de los usuarios. Es decir, quiero un cifrado de extremo a extremo para mi aplicación cliente-servidor.

El cliente cifra los datos del usuario con una clave criptográfica derivada de la contraseña del usuario, por lo que es importante que el servidor no pueda averiguar la contraseña porque eso permitiría al servidor descifrar los datos del usuario. Por lo tanto, el cliente utiliza el protocolo de contraseña remota segura para evitar enviar la contraseña al servidor. Hasta ahora todo bien.

Aquí es donde mi diseño se vuelve un poco heterodoxo. El problema es que los usuarios en general son muy malos en la creación de contraseñas (generalmente, eligen una contraseña de la lista de las 10,000 contraseñas principales), lo que facilitaría que un atacante que tiene acceso al servidor descifre los datos del usuario. Por lo tanto, planeo generar un conjunto aleatorio de caracteres y agregarlos al campo ID de usuario, por lo que el usuario tendrá que iniciar sesión con algo como estas credenciales:

User ID: John-CPE4E38J
Password: snoopy

Pero antes de procesar estas credenciales, el código de inicio de sesión mueve los caracteres aleatorios a la contraseña para que la biblioteca de autenticación de SRP subyacente vea esto:

User ID: John
Password: snoopy-CPE4E38J

Además, el cliente ofrece recordar la ID de usuario (es decir, John-CPE4E38J) para que la mayoría de las veces el usuario solo tenga que recordar su contraseña.

¿Qué piensas de este enfoque? ¿Estoy rompiendo la regla del algoritmo de no implementar tu propia seguridad? ¿O es esta una buena manera de fortalecer la seguridad de mi aplicación?

    
pregunta Mark 29.01.2015 - 14:53
fuente

3 respuestas

7

Tu idea es una especie de hack. Pero si está limitado por el software existente, que requiere que las credenciales consten de solo dos campos, entonces podría ser un truco adecuado.

Si está escribiendo el código del cliente y no está sujeto a restricciones arbitrarias, es mejor que utilice tres campos separados para establecer una clara distinción entre el propósito de cada una de las tres cadenas.

Tener autenticación depende tanto de un secreto almacenado en la máquina cliente como de que un secreto recordado por el usuario es un buen enfoque. Este es un tipo de autenticación de dos factores, porque el usuario necesita tanto la máquina en la que se almacena el secreto como el conocimiento de la contraseña.

Uno tiene que preocuparse por mantener una copia de seguridad del secreto almacenado en la máquina. Esto es importante porque si lo pierdes, ya no habrá forma de descifrar los datos, por lo que efectivamente se pierden todos sus datos.

También debe hacer uso de una función de derivación de clave, que requiere algo de tiempo de CPU en el cliente para derivar una clave real a partir de los datos secretos. Si esto requiere 100 ms de tiempo de CPU, el usuario apenas lo nota, pero la necesidad de 100 ms de tiempo de CPU para cada intento de contraseña ralentizará significativamente al atacante. Es importante que el tiempo de CPU se gaste en el cliente en lugar de en el servidor, porque si está en el servidor, se convierte en un vector DoS.

Cifrar todos los datos directamente con una clave derivada de la contraseña del usuario significa que un cambio de contraseña requerirá que todos los datos se vuelvan a cifrar. Por otro lado, mantener una clave fija para cifrar los datos y cifrar esa clave mediante la clave derivada de la contraseña del usuario es más eficiente, pero tiene una vulnerabilidad de seguridad sutil.

Un atacante que obtuvo una copia de los datos del servidor podría ser capaz de forzar las contraseñas de algunos usuarios. Si el atacante obtiene otra copia de los datos del servidor más tarde, los datos de los usuarios aún se pueden descifrar, incluso si el usuario ha elegido una contraseña más fuerte mientras tanto. Esto significa que los datos que se cifraron solo después de que el usuario cambió a una contraseña más segura siguen siendo vulnerables a los ataques contra la antigua contraseña más débil.

Este problema se puede resolver almacenando los datos en una estructura de árbol donde cada nodo está cifrado con una clave almacenada en el nodo principal, y la raíz se cifra utilizando una clave derivada de los datos secretos.

También tenga en cuenta que los datos secretos que almacena en el cliente deben cambiar, siempre que cambie la contraseña. De lo contrario, no obtendrás el beneficio de seguridad deseado.

Supongamos que un usuario inicialmente tenía una contraseña débil, y un atacante pudo forzar el secreto que se almacenó en el cliente debido a esa contraseña débil. Si el usuario cambia a una contraseña más segura, pero el secreto almacenado permanece sin cambios, el atacante solo debe forzar la contraseña nueva y no la combinación de contraseña y secreto almacenado.

    
respondido por el kasperd 30.01.2015 - 10:27
fuente
29

Sí: estás reescribiendo la seguridad aquí. Ya se sabe que varias funciones de derivación de contraseña funcionan, la más conocida es PBKDF2 . Use eso en lugar de su esquema personalizado.

Lo que intentas hacer es, en esencia, eliminar la contraseña (con un breve salto) y almacenar el valor de sal en el nombre de usuario. No es realmente una mejora.

Algo más que quizás quieras replantear: con tu sistema, la clave de cifrado se deriva directamente de la contraseña del usuario. Esto significa que un atacante no solo puede intentar descifrar los datos del usuario al intentar usar listas de contraseñas conocidas (incluso si usar una función de derivación de clave basada en contraseña lo dificulta), sino que también evita que el usuario cambie su contraseña (de lo contrario , necesitas volver a cifrar todos los datos del usuario).

Sin saber más acerca de sus requisitos y el entorno, es difícil sugerir la mejor manera de proceder, pero, por lo que describe, estoy seguro de que esto puede mejorarse enormemente. Por lo tanto, sugiero que contrate a un especialista para que lo ayude a encontrar una solución adecuada en este caso.

    
respondido por el Stephane 29.01.2015 - 15:43
fuente
6

Su enfoque es muy similar al concepto de salt en criptografía. Antes de hablar sobre lo que es un salt, asumo que usted, al menos, está almacenando el hash de las contraseñas de los usuarios, y no las contraseñas en texto sin formato. De lo contrario, su solución es completamente inútil.

Una sal es simplemente datos aleatorios que se utilizan al hashear una contraseña, por ejemplo, para fines de almacenamiento. Su cadena aleatoria agregada al nombre de usuario es efectivamente una sal. Entonces, si simplemente estuviera almacenando los hashes sin sal de las contraseñas de los usuarios, entonces, de alguna manera, está fortaleciendo un poco la seguridad de su aplicación, ya que al menos la lista de hashes de contraseña no sería vulnerable a los ataques de diccionario, en principio. Pero solo en ese caso. De todos modos, hay formas estándar de proteger listas de hashes de contraseñas, que no implican revelar la sal durante la autenticación.

Sin embargo, si su intención era dificultar la adivinación de la contraseña, entonces no proporciona ninguna seguridad adicional, ya que el atacante proporciona una cadena aleatoria durante la autenticación.

    
respondido por el cygnusv 29.01.2015 - 15:51
fuente

Lea otras preguntas en las etiquetas