¿Las contraseñas de hash con bcrypt y un sal constante son más inseguras que SHA1?

3

He creado una API que permite a los usuarios enviar datos cifrados para que se almacenen en la nube. Para recuperar sus datos, la API requiere que el usuario proporcione solo el ID de objeto MongoDB que se les proporcionó cuando se enviaron inicialmente sus datos, más el hash SHA1 de la contraseña que utilizaron para cifrar los datos. Elegí usar tanto el ID de objeto como el hash de contraseña como una clave única para evitar que los usuarios soliciten datos a través de la API, ya que los distintos ID de objeto no son complejos y fáciles de adivinar.

Ahora he cambiado el método hash de SHA1 a bcrypt porque es más seguro, pero eso ha presentado un problema. Debido a que bcrypt genera una sal diferente cada vez, el hash siempre tiene un significado diferente, ya no puedo usar el hash generado para identificar los datos del usuario en la base de datos, a menos que fuerce a la aplicación a usar la misma sal cada vez que genere un hash bcrypt. Nota: si uso un sal constante, el público lo sabrá ya que el código fuente es de código abierto.

Mi pregunta es, si uso un salt constante con bcrypt para generar hashes de contraseña, ¿esto hace que los hashes sean más fáciles de descifrar que usar SHA1 como lo era originalmente, y si no es así, sigue siendo un enfoque poco práctico para crear hashes de contraseña seguros? ?

Alternativamente, ¿existe un mejor enfoque para especificar una clave única para los datos del usuario en la base de datos sin pedirle más información al usuario?

Editar: Al tratar de mantener la pregunta lo más simple posible, me he dado cuenta de que realmente no he brindado suficiente contexto para explicar por qué elegí el enfoque que tengo, así que aquí hay un poco más. es de esperar que la información sea más clara y que las personas puedan proporcionar una respuesta lo más precisa posible.

La intención es crear un servicio seguro y anónimo para respaldar la aplicación, que puede ser ejecutado por cualquier persona, en cualquier lugar. La aplicación y la API son de código abierto y, por lo tanto, cualquier persona que desee proporcionar su espacio de servidor para otros usuarios de la aplicación puede ejecutar su propia instancia de la API. Los usuarios de la aplicación pueden apuntarla a la URL de la API de su elección, lo que les permite usar cualquier instancia pública de la API, o incluso alojar una instancia en su propio servidor que solo ellos pueden usar.

Debido a que los datos del usuario pueden estar en cualquier servidor público, es importante que los datos estén cifrados del lado del cliente y que el usuario nunca envíe su contraseña de texto simple por el cable, en caso de que el propietario del servidor API (o cualquier otra persona) desee Para descifrar los datos de usuario que se alojan. El servicio es anónimo por razones de seguridad y conveniencia, por lo tanto, el usuario de la aplicación no tiene que proporcionar una dirección de correo electrónico ni ninguna otra información de identificación, simplemente hace clic en un botón de la aplicación y sus datos se cifran con su contraseña, que se envía a la API junto con su contraseña de hash:

Ejemplo de publicación del cuerpo:

{
    "data":"DWCx6wR9ggPqPRrhU4O4oLN5P09onApoAULX4Xt+ckxswtFNH/QQ+Y/RgxdU+8+8/muo4jo/jKnHssSezvjq6aPvYK+EAzAoRmXenAgUwHOjbiAXFqF8gScbbuLRlF0MsTKn/puIyFnvJd...",
    "passwordHash":"d4de34f15aeadfb34bdf1fbbd57134b2baeb142c"
}

Respuesta:

{
    "id":"507f191e810c19729de860ea",
    "lastUpdated":"2016-07-06T12:43:16.866Z"
}

La entrada mongodb se vería así:

{
    "id": "507f191e810c19729de860ea",
    "passwordHash": "d4de34f15aeadfb34bdf1fbbd57134b2baeb142c",
    "data": "DWCx6wR9ggPqPRrhU4O4oLN5P09onApoAULX4Xt+ckxswtFNH/QQ+Y/RgxdU+8+8/muo4jo/jKnHssSezvjq6aPvYK+EAzAoRmXenAgUwHOjbiAXFqF8gScbbuLRlF0MsTKn/puIyFnvJd...",
    "lastUpdated": "2016-07-06T12:43:16.866Z"
}

Un usuario puede recuperar sus datos con una solicitud GET para /api/data/{id}/{passwordHash} , así que para el ejemplo anterior:

/api/data/507f191e810c19729de860ea/d4de34f15aeadfb34bdf1fbbd57134b2baeb142c

Respuesta:

{
    "data":"DWCx6wR9ggPqPRrhU4O4oLN5P09onApoAULX4Xt+ckxswtFNH/QQ+Y/RgxdU+8+8/muo4jo/jKnHssSezvjq6aPvYK+EAzAoRmXenAgUwHOjbiAXFqF8gScbbuLRlF0MsTKn/puIyFnvJd...",
    "lastUpdated":"2016-07-06T12:43:16.866Z"
}

Dado que el valor de id (ID de objeto MongoDB) no es demasiado complejo, un usuario malintencionado puede potencialmente adivinar la identificación de otra persona y recuperar sus datos a través de la API. Por esa razón, decidí usar el ID junto con el hash de la contraseña del usuario como la clave para que a un usuario malintencionado le resulte más difícil adivinar la clave exclusiva de otra persona. Sin embargo, si solo utilizara la identificación del objeto como clave e incluso si pudieran adivinar la identificación de otro usuario, solo recuperarían sus datos cifrados (no el hash de la contraseña), que luego necesitarían descifrar antes de leer los datos. ¿Sería esta una mejor alternativa para almacenar el hash de contraseña? Irónicamente, esto resolvería el problema de bcrypt como si no estuviera almacenando los hashes de contraseña en el servidor, no necesitaría hash la contraseña (utilizada para cifrar los datos del lado del cliente) en absoluto ...

En conclusión, la pregunta en relación con mi aplicación / api es mucho más compleja que la pregunta en curso, pero realmente no pude pensar en cómo encuadrarla correctamente (tal vez necesito cambiar la pregunta ). Sin embargo, si alguien tiene alguna opinión sobre los aspectos de seguridad de mi enfoque teniendo en cuenta los requisitos, le agradecería mucho la aportación.

    
pregunta nero120 11.07.2016 - 18:16
fuente

3 respuestas

6

Si está utilizando un sal constante, entonces no es bcrypt:

  

Un requisito importante de cualquier implementación de bcrypt es que explote todo el espacio de sal de 128 bits.

- Un esquema de contraseña adaptable al futuro

  

Debido a que bcrypt genera una sal diferente cada vez, el hash siempre tiene un significado diferente, ya no puedo usar el hash generado para identificar los datos del usuario en la base de datos

Claro que puedes, ya que ya tienes la sal del hash anterior, úsalo al generar el nuevo hash.

    
respondido por el Jim 11.07.2016 - 19:28
fuente
6
  

Disclaimar: Tenga en cuenta que esta respuesta se escribió antes de agregar más detalles a la pregunta. Por lo tanto, algunos puntos ya no se aplican, mientras que otros aún lo hacen.

Problemas con su enfoque

  

[...] de la contraseña que usaron para cifrar los datos.

¿Está utilizando contraseñas como claves de cifrado? Esa no es una buena idea, ya que las contraseñas elegidas por los usuarios tienen poca entropía y, por lo tanto, pueden ser forzadas de manera bruta.

  

Para recuperar sus datos, la API requiere que el usuario suministre [...] el hash SHA1 de la contraseña [...].

El usuario debe enviar la contraseña, no el hash. Hacer que el usuario envíe los hash efectivamente hace que el hash sea la contraseña, lo que significa que usted almacena las contraseñas efectivas (es decir, el hash) desprotegidas. Busque "pasar el hash" para obtener más información.

Pero, ¿cómo se puede descifrar si la contraseña se utilizó para el cifrado y solo se obtiene el hash del usuario?

  

Debido a que bcrypt genera una sal diferente cada vez, el hash siempre tiene un significado diferente, ya no puedo usar el hash generado para identificar los datos del usuario en la base de datos, a menos que fuerzo a la aplicación a usar la misma sal cada vez que genera una bcrypt hash.

¿Por qué usarías el hash para identificar los datos? Usted utiliza el ID de objeto MongoDB para eso. Utiliza la contraseña y el hash para la autenticación.

Si no pasa el hash, sino que pasa la contraseña, puede usar bcrypt con sales individuales para la autenticación. Genera uno al azar para cada usuario y guárdalo en la base de datos. Luego, cuando el usuario envía una contraseña, la hash usando ese salt, y la compara. Cualquier biblioteca que haga bcrypt debería tener una función para esto.

Un resumen de cómo hacer esto bien

Cuando el usuario guarda sus datos en su servidor, proporciona una contraseña. Usted genera un único sal aleatorio y lo almacena en la base de datos. Luego hash la contraseña usando bcrypt y esa sal para obtener una clave de cifrado. Utiliza esta clave para cifrar los datos.

Cuando el usuario desea acceder a los datos, vuelve a proporcionar la contraseña. Lo hash con bcrypt y el salt almacenado para obtener la clave. Lo usas para descifrar los datos. Finalmente, verifica un MAC para ver si el descifrado sí funcionó: si la contraseña fuera incorrecta, obtendría la clave incorrecta y luego el MAC no coincidirá.

Tenga en cuenta que aquí hay un montón de letra pequeña para esto, así que no tome los dos párrafos anteriores como guía completa.

Finalmente, ¿estás seguro de que quieres rodar aquí? Probablemente ya existen soluciones que hacen lo que usted quiere hacer. Si programa su propio riesgo, cometerá un pequeño error y le robarán todos los datos de sus usuarios.

    
respondido por el Anders 11.07.2016 - 19:24
fuente
2

¡No deberías usar tampoco!

El uso de una sal constante anula el propósito de usar bcrypt. Utilice una sal variable! Al igual que SHA1, es fácil de romper. Es como preguntar: ¿qué es más seguro, una caja de madera o una caja de acero reforzada a prueba de termitas con una puerta de madera? Excelente explicación de Tom Scott.

En mi humilde opinión, su código es probablemente vulnerable a la inyección de SQL debido a los olores de su código. Huele mucho Compruebe su código para la inyección SQL, XSS, CSRF, etc.

(todos estos han sido descifrados.)

Addendum

Si va a cifrar datos, use un sistema de clave pública / privada. Sin embargo, esto evitará que todos, excepto el usuario, vean los datos, incluido usted el administrador. No cifre los datos con contraseñas: cifre los datos con las claves adecuadas. Recomendaría RSA-2048 si la información no es tan confidencial, RSA-4096 para la seguridad garantizada con estaño (la NSA usa esto) y RSA-8192 si sabe que los espías del gobierno intentarán descifrar la información de su usuario y / o billones de dólares se destinarán a la seguridad de su base de datos.

Aún puede utilizar el hash para identificar los datos del usuario, solo incluya el salt con los datos y el hash de los datos con el salt.

Podría hacer que el cliente genere una firma para verificar la identidad del usuario y podría actuar como una autoridad de certificación. Y en lugar de información de identificación personal, podría usar un UUID aleatorio. Pero ser capaz de identificar al usuario anula el propósito del anonimato.

    
respondido por el noɥʇʎԀʎzɐɹƆ 11.07.2016 - 18:24
fuente

Lea otras preguntas en las etiquetas