Argumentos que prueban que un esquema de hashing es suficiente

3

Actualmente estamos trabajando en una nueva aplicación de servidor que se comunicará con las aplicaciones cliente en muchos sistemas diferentes. Para esto queríamos implementar un nuevo esquema de hashing de contraseña.

He investigado bastante, incluida la lectura de muchas preguntas sobre seguridad.SE y crypto.SE, sobre el hashing de las contraseñas. Después de esta investigación, he encontrado el siguiente esquema de hash:

Usaremos PBKDF2 como algoritmo de hashing. La elección para esto radica principalmente en que esté disponible directamente en .NET Framework. He analizado tanto bcrypt como scrypt , pero como ambos necesitan bibliotecas de terceros, solo hemos ido con PBKDF2 .

Con el uso de PBKDF2 también está la sal libre que se obtiene al generar un hash por primera vez.

La pregunta entonces era cómo guardar los datos en la base de datos. Teníamos dos opciones:

  • Guarde cada valor por separado, es decir, hash, sal, iteraciones y algoritmo.
  • O guárdelo como una sola cadena.

Fuimos con el valor de cadena única que se ve de la siguiente manera:

<algorithm>$<iterations>$<salt>$<hash>

Esto es similar a cómo, por ejemplo, Django lo hace.

Lo implementé así y escribí un informe con nuestras elecciones y argumentos. Pero ahora me sale preguntas sobre el diseño. Por ejemplo, algunos se preguntan por qué la sal se guarda tan claramente, ¿no sería mejor combinar la sal y el hash en una sola cadena para que sea menos evidente para los atacantes?

Por lo general, estos casos hacen suposiciones donde los atacantes solo tienen la base de datos y tal. Si bien afirmo que siempre debemos mirar el peor de los casos y asumir que los atacantes tienen tanto el código como la base de datos. También afirmo que la sal está ahí para negar el efecto de las tablas de arco iris y las tablas de búsqueda. Y el número de iteraciones es el de los ataques de fuerza bruta.

Pero como no soy un profesional de la seguridad, lo que digo puede ignorarse fácilmente (aunque esto se aplica a cualquier argumento en Internet;)).

Por lo tanto, necesito algo que pueda mostrar que lo que creamos es una forma correcta de hacerlo.

Acabo de implementar muchas cosas que encontré en Internet, pero no tengo pruebas (científicas) de que esto sea suficiente.

    
pregunta Chrono 20.02.2013 - 16:49
fuente

3 respuestas

5

La sal no necesita ser secreta, porque si fuera secreta, la llamaríamos clave .

Hacer las cosas correctamente y convencer a otras personas de que las hiciste correctamente son dos cuestiones distintas. En cualquier caso, siempre asumimos que el atacante conoce tanto el contenido de la base de datos como el código, porque eso es lo que sucede en la práctica. Mantener el código en secreto es muy difícil, ya que existe como binarios y códigos fuente en muchos lugares (el servidor en sí, las máquinas de los desarrolladores, las cintas de copia de seguridad, los heads de los desarrolladores, y posiblemente en toda Internet si el código es de código abierto). Asumir que el código es secreto no parece ser una buena base para la seguridad.

Por lo tanto, puede (y debe) asumir que el atacante sabrá qué parte de su cadena almacenada es la sal, y qué parte es el valor de hash. Por lo tanto, también puede utilizar una codificación clara y precisa, como sugiere.

Para la parte convincente , cite NIST (la organización federal de los EE. UU. que se ocupa, en particular, de los estándares de criptografía), publicación especial 800-132 . Consulte, por ejemplo, la página 3 de ese documento, donde la sal se define como:

  

Un valor binario no secreto que se usa como entrada para la clave   La función de derivación PBKDF especificada en esta Recomendación a   permite la generación de un gran conjunto de claves para una contraseña determinada.

(énfasis en "no secreto").

    
respondido por el Thomas Pornin 20.02.2013 - 20:30
fuente
2

Simplemente añadir la sal al hash en lugar de tenerlos claramente establecidos es efectivamente seguridad por oscuridad y agrega un valor mínimo, pero la otra pregunta es si existe alguna razón para no hacerlo. Si sabes cómo analizarlo, es trivial, sin embargo, está formateado, por lo que no hay inconveniente en tenerlo directamente concatenado.

Dicho esto, si existe la posibilidad de que el algoritmo o la longitud puedan cambiar en el futuro, tener un campo de ancho fijo sería negativo. Ya que también está almacenando el algoritmo utilizado, esta es quizás una buena razón para no simplemente concatenar los valores. De cualquier manera, no hay una implicación de seguridad significativa para explicar que un valor en particular es la sal en lugar de tratar de ofuscarlo. El secreto de la sal no es necesario para la seguridad del sistema.

    
respondido por el AJ Henderson 20.02.2013 - 17:16
fuente
0

Debe almacenar toda esta información (algoritmo, iteraciones, sal, hash) para cada usuario individualmente, por lo que debe estar en la base de datos. La sal tiene que ser única para cada usuario. Si bien muchas entradas tendrán el mismo algoritmo y el número de iteraciones, con el tiempo no habrá un solo valor para todos los usuarios. La razón es que a medida que pase el tiempo, querrá aumentar el número de iteraciones (cada vez que actualice su servidor) y, ocasionalmente, cambiar el algoritmo (por ejemplo, cambiar a Scrypt si una nueva versión de .NET lo ofrece). Pero solo puedes hacerlo cuando un usuario inicia sesión, porque necesitas la cadena de contraseña original para construir el nuevo hash. Dado que esto es impredecible, cuando un usuario se autentica, necesita recuperar el algoritmo, el recuento de iteraciones y la sal, usar estos más la contraseña ingresada por el usuario para calcular el hash y comparar ese hash con el hash de referencia almacenado en la base de datos. Así que necesitas poder analizar todos estos campos.

La seguridad del almacenamiento de contraseñas no se basa en el significado de los campos que están ocultos para los atacantes. Generalmente, el atacante sabe cómo funciona la aplicación (puede estar ejecutando la aplicación en un servidor de prueba o incluso tener el código fuente). Incluso para una aplicación interna, el atacante puede haber creado algunas cuentas y puede probar fácilmente varias combinaciones.

"Que sea menos obvio para los atacantes" es muy obviamente seguridad a través de la oscuridad . Es similar a poner tu cabeza en la arena y asumir que tu atacante hará lo mismo. No tiene ningún sentido ocultar información que sea irrelevante para la seguridad del sistema.

Por otro lado, existen riesgos y costos asociados con la no disposición clara de los campos. Con el tiempo, necesitará mantener su aplicación, tal vez tendrá que volver a escribir el módulo de autenticación en algún momento. Cuanto más simple sea la forma de codificar, más fácil será el mantenimiento. Seguir un esquema estándar es una buena idea (los esquemas separados por dólares no son específicos de Django). El uso de una compleja codificación interna aumenta el riesgo de que se equivoque, lo que se traduce en hashes de contraseña ilegibles o, por el contrario, en hashes truncados fáciles de descifrar.

    
respondido por el Gilles 20.02.2013 - 20:08
fuente

Lea otras preguntas en las etiquetas