¿Cómo hacer el hashing de la contraseña del lado del cliente con BCrypt? [duplicar]

16

Estoy migrando una aplicación antigua que usaba hash MD5 a Spring Security con codificación de contraseñas de BCrypt. Quiero codificar la contraseña en la página de creación de nuevo usuario, cambiar la página de contraseña y en la página de inicio de sesión antes de que se envíe a la red.

Sé que HTTPS puede resolver el problema, pero aún así se me indica que codifique la contraseña antes de enviarla a través de la red según nuestras pautas de organización.

¿Cuál podría ser la mejor solución posible para hacer hashing de las contraseñas usando JavaScript?

Para explicarlo más a fondo, estoy usando JCryption API para cifrar la contraseña usando AES, por lo que el valor transmitido a través de la red es AES(SHA1(MD5(plain password))) ahora quiero reemplazar MD5 con Bcrypt solamente. El resto de las cosas se mantienen sin cambios. ¿Funcionará este enfoque contra "El hombre en el ataque central"?

    
pregunta Amit 08.07.2015 - 11:19
fuente

5 respuestas

11

bcrypt no está diseñado para este tipo de hashing del lado del cliente

Una propiedad clave de bcrypt es que, cuando se ejecutan dos veces independientes con el mismo texto sin formato, la mayoría de las implementaciones producirán hashes diferentes. Esto se debe al uso de una sal, que está diseñada para hacer que sea difícil ver si dos usuarios diferentes tienen la misma contraseña.

En contraste, los formularios de inicio de sesión necesitan recibir los mismos datos cada vez. Después de todo, ¿de qué otra manera verificarías que la contraseña que el usuario escribió hoy es la misma que escribió ayer?

Entonces, tiene un algoritmo diseñado para producir datos diferentes cada vez, y lo está introduciendo en una aplicación que necesita verificar que los datos son los mismos mismos hora. Probablemente sea una indicación de que el algoritmo no se está utilizando como se esperaba.

Lo que idealmente deberías estar haciendo es usar bcrypt para las contraseñas de hash en el servidor . Para eso se diseñó bcrypt: proteger las contraseñas de los usuarios en momentos en que el texto sin formato no está en la memoria, que es, con mucho, el estado más común (por ejemplo, los volcados de base de datos solo revelarán la contraseña con hash, no el texto sin formato, si se implementan correctamente). / p>

Personalmente también veo algo de valor en el hash del lado del cliente, porque ayuda a proteger contra los atacantes que pueden detectar el tráfico (o que tienen acceso al servidor). Sin embargo, no conozco una manera de hacer que el hash del lado del cliente sea tan seguro como el bcrypt del lado del servidor, razón por la cual aún debería usar el bcrypt del lado del servidor.

Si debe usar el lado del cliente de bcrypt, use un sal estático

Si VAS a usar bcrypt para el hashing del lado del cliente de un formulario de inicio de sesión, y quieres que sea un reemplazo directo para MD5, debes usar un sal estático. Especialmente si lo estás pasando a través de SHA1, ya que eso estropearía el bcrypt salt así como la propia información de hash.

Esto rompe varias suposiciones de diseño de bcrypt (por ejemplo, usar siempre una sal aleatoria), por supuesto.

Personalmente recomendaría usar el nombre de usuario como un salt (por lo que es difícil saber si dos usuarios diferentes tienen la misma contraseña); sin embargo, no conozco ninguna investigación que se haya hecho sobre la salazón en este contexto.

AES (o cualquier cifrado simétrico) aquí también es inútil

Tenga en cuenta que AES es un algoritmo simétrico, lo que significa que necesita la misma clave para descifrar y para cifrar los datos.

¿Qué significa esto para ti? Bueno, probablemente tenga su clave de cifrado en la fuente de JavaScript, que se entrega a cualquier cliente que visite su página de inicio de sesión. AES es un cifrado simétrico, por lo que su clave de cifrado (que es idéntica a la clave de descifrado) debe mantenerse privada. En otras palabras, su clave privada es conocida en todo el mundo : no proporciona seguridad en este punto.

Lo que debería usar en su lugar es criptografía de clave pública, como PGP o HTTPS (técnicamente, HTTPS utiliza un enfoque híbrido). En serio, simplemente use HTTPS , a menos que su organización se niegue a permitirle tener un certificado SSL, por alguna razón. Tenga en cuenta que PGP no protegerá realmente contra ataques MITM activos, pero al menos protegerá contra escuchas ilegales.

    
respondido por el Ethan Kaminski 09.07.2015 - 02:44
fuente
44
  

Sé que HTTPS puede resolver el problema, pero aún tengo instrucciones para codificar la contraseña antes de enviarla a través de la red según nuestras pautas de organización.

Esto realmente define tu situación.

Básicamente, tiene una solución simple que debería usar de todos modos (use HTTPS), aunque solo sea porque sin HTTPS un atacante activo podría secuestrar la conexión después del paso de autenticación, independientemente de cualquier "codificación" y hashing que use para la contraseña (un atacante que esté en posición de hacer un ataque Man-in-the-Middle tendrá éxito independientemente de cuánto bailas ritualmente con funciones hash y cifrado). Entonces, también tiene una guía que es a la vez idiota y administrativamente inevitable. Su problema es entonces: ¿cómo puede hacer las cosas correctamente y seguir cumpliendo con la "pauta"?

Tenga en cuenta que la guía tiene poco sentido en varios niveles. No solo la falta de SSL hace que el protocolo sea vulnerable al secuestro; pero también cualquier tipo de "codificación" no hace nada bueno contra atacantes pasivos. La razón es que si el protocolo es "el cliente muestra la contraseña 'codificada'", entonces un interceptor pasivo simplemente mirará esa "contraseña codificada" y la enviará por sí mismo, por lo tanto, ese tipo de codificación no mejora la seguridad en ningún caso. camino. Simplemente hace que algunas personas se sientan más seguras, ya que entienden la criptografía como una especie de salsa barbacoa ("cuanto más esparcimos en todas partes, mejor se pone").

Lo que sugiero es que hagas lo siguiente:

  1. Primero, intente vender la idea de que "HTTPS" encarna la "codificación". En otras palabras, al enviar la contraseña dentro de un túnel SSL, ya está cumpliendo con la directriz, ya que la contraseña está debidamente codificada (y, en realidad, cifrada ), junto con el resto de los datos.

  2. Si la infestación por estupidez es más grave y algún auditor (llamémosle Bob) todavía tiene un problema con su falta de "codificación", entonces intente aplicar alguna codificación reversible en el lado del cliente. P.ej. antes de enviar la contraseña, aplique Base64 . Esto significa que si la contraseña es "bobsucks", lo que se enviará (dentro del SSL, por supuesto) será "Ym9ic3Vja3M=", y Bob estará más contento, porque la última cadena es obviamente a mucho más seguro.

El punto importante aquí es que dado que el requisito no tiene sentido, la solución tampoco tendrá mucho sentido.

    
respondido por el Tom Leek 08.07.2015 - 14:33
fuente
25

No tienes seguridad sin autenticación

  

Solo para explicarlo más a fondo, estoy usando JCryption API para cifrar   la contraseña utilizando AES, por lo que el valor transmitido a través de la red es   AES (SHA1 (MD5 (contraseña simple))) ahora quiero reemplazar MD5 con Bcrypt   solamente. El resto de las cosas se mantienen sin cambios. Este enfoque funciona incluso   contra "El hombre en el ataque central" .

No, no lo hace. No puedo expresar esto con suficiente fuerza. Ahora no puedo convencerlo de que use https (es posible que ni siquiera tenga una opción), pero espero poder convencerlo de que es absolutamente inseguro y de cualquier creencia que tenga sobre Proporcionar algo de seguridad es incorrecto. Si se le obliga a seguir adelante sin usar TLS / SSL, al menos puede dejar muy claro a todos los involucrados que el sistema es vulnerable y debe describirse como "fácil de evitar, sentirse bien y con buena seguridad". Un niño de secuencias de comandos que ejecuta un punto de acceso MITM en su Starbucks local podría falsificar a sus usuarios y robar credenciales o secuestrar sesiones para que no sea algo que requiera habilidades sofisticadas o ataques complejos.

Si el canal de comunicación no es seguro, no debe esperar que el código que envíe sea el que realmente ejecuta el cliente. Hay una razón por la que se llama https (http seguro) no solo httpe (http cifrado), la seguridad es más que solo cifrado. La comunicación de cifrado sin autenticación no tiene sentido.

Algunas cosas para pensar:

  • Sin https, ¿cómo saben sus usuarios que están en su página de inicio de sesión?
  • ¿Cómo sabe que un atacante no ha modificado la página de inicio de sesión enviada al usuario para enviarle una copia de texto simple de las credenciales antes de cifrarla y enviársela?
  • Está intentando cifrar el hash doble de la contraseña. ¿Cómo va a transmitir de manera segura la clave de cifrado?

¿Qué pasa si hago mi propia autenticación personalizada además del cifrado

No es tan simple. Arrancar un canal seguro sobre uno inseguro no es un problema trivial. En teoría, podría crear un protocolo personalizado que replique todos los aspectos de https, incluida la negociación del protocolo, la autenticación del servidor, la infraestructura de clave pública, el intercambio de claves, el cifrado, la integridad y revocación de los mensajes (y estoy seguro de que olvidé muchos más). Una vez hecho esto, sería tan grande y complejo como TLS. Supongamos también que tenía menos defectos que cualquier implementación de TLS y que podría hacerlo en menos de un par de años, todavía tendría un problema casi imposible. ¿Cómo vas a llevar estos componentes del lado del cliente al cliente? "Oh, seguro que el cliente lo descargue de forma segura ... eh espera". Si la comunicación segura a través de un canal inseguro parece fácil, entonces honestamente no has buscado lo suficiente, las tortugas están completamente abajo.

Ahora déjeme ser claro, TLS tiene muchos problemas y el sistema de CA también tiene muchos problemas. Ciertamente, no voy a pretender que es perfecto, pero la comunicación segura es un problema tan grave como el de los huevos y la gallina que es la mejor solución que tenemos.

El hashing del lado del cliente se puede hacer a través de https

Por su redacción parece que considera que la pregunta es "hashing del lado del cliente O hashing del lado del servidor sobre https", pero espero que pueda ver que es una falacia. Necesita https independientemente de cómo autentique a sus usuarios. Entonces, si acepta que necesita https, entonces la pregunta es "¿Por qué o cuándo tendría sentido utilizar el hashing del lado del cliente (a través de https) en lugar del hashing del lado del servidor (a través de https)? En la mayoría de los casos, no lo haría. el hashing del lado del cliente es más complejo y no más seguro, pero tiene una ventaja y es que el servidor no tiene conocimiento de la contraseña, lo que no es el caso del hashing del lado del servidor. En algunos escenarios, usted desea servidor) para ser denegable. No puede perder una clave que no tiene, y no puede ser forzado a descifrar los archivos de un cliente si nunca le dieron la clave de descifrado. Por lo tanto, existen escenarios en los que puede ser obligatorio. requisito, pero debe ser parte del diseño del proyecto, no una decisión arbitraria. Si tiene preguntas específicas sobre cómo manejar los escenarios de conocimiento cero, sería mejor hacerlo como una nueva pregunta.

    
respondido por el Gerald Davis 08.07.2015 - 15:00
fuente
9

La mejor solución es: no.

Si está enviando las contraseñas a través de HTTPS, el hashing no proporciona seguridad adicional.

Si está enviando las contraseñas a través de HTTP simple, un atacante puede agarrar la contraseña con hash y usarla para iniciar sesión; de forma alternativa, pueden manipular el JavaScript para enviarles la contraseña antes de realizar el hash. En cualquier caso, el hashing de la contraseña no proporciona seguridad.

    
respondido por el Mark 08.07.2015 - 11:27
fuente
4

Como parece comprometido a implementar esta guía, responderé directamente a su pregunta. Pero entiendo que BCrypt y MD5 son muy diferentes. BCrypt realiza deliberadamente un trabajo sustancial, mientras que el MD5 hace mucho menos, por lo que tendrá que hacer frente a las promesas:

<!-- https://github.com/nevins-b/javascript-bcrypt -->
<script src='bCrypt.js'></script>
<script src='isaac.js'></script>
<script>
  // ... your code, then:
  var bcrypt = new bCrypt();
  bcrypt.hashpw('plain password', bcrypt.gensalt(), function (hashed) {
      var cipher = AES(SHA1(hashed));
      // now you have your "secure" hash
  });
</script>

Le insto a que considere el sabio consejo en las otras respuestas. Los escenarios en los que esta guía agrega valor son raros, así que pregúntese: ¿Por qué invertir el doble trabajo en una infraestructura redundante que no agrega seguridad y ralentiza la experiencia del usuario?

Referencias:

  1. El cifrado de transporte protege todos los secretos .

  2. Enviar un hash es equivalente a enviar una contraseña y generar un hash seguro es necesariamente lento .

  3. ¿La resistencia de fuerza bruta de bcrypt contra MD5 para el hashing de contraseñas? y resultados de las pruebas de rendimiento del algoritmo hash .

respondido por el bishop 08.07.2015 - 19:17
fuente

Lea otras preguntas en las etiquetas