¿Hay alguna implementación de javascript SHA-256 que generalmente se considere confiable?


Estoy escribiendo un inicio de sesión para un foro, y necesito hash la contraseña del lado del cliente en javascript antes de enviarla al servidor. Estoy teniendo problemas para averiguar en qué implementación de SHA-256 puedo confiar. Esperaba que hubiera algún tipo de script autorizado que todos usaran, pero estoy encontrando un montón de proyectos diferentes, todos con sus propias implementaciones.

Me doy cuenta de que usar el cripto de otras personas siempre es un salto de fe a menos que esté calificado para revisarlo usted mismo, y que no hay una definición universal de" confiable", pero esto parece algo lo suficientemente común e importante como para que deba haber algún tipo de consenso sobre qué usar. ¿Soy ingenuo?

Editar ya que aparece mucho en los comentarios: Sí, hacemos un hash más estricto de nuevo en el lado del servidor. El hash del lado del cliente no es el resultado final que guardamos en la base de datos. El hashing del lado del cliente se debe a que el cliente humano lo solicita. Ellos no han dado un específico razón por la cual, probablemente les gusta la exageración.

Author: jono, 2013-08-19

7 answers

El Stanford JS Crypto Library contiene una implementación de SHA-256. Mientras que crypto en JS no es realmente un esfuerzo tan bien investigado como otras plataformas de implementación, esta es al menos parcialmente desarrollada y hasta cierto punto patrocinada por Dan Boneh, quien es un nombre bien establecido y confiable en criptografía, y significa que el proyecto tiene alguna supervisión por parte de alguien que realmente sabe lo que está haciendo. The project is also supported by the NSF.

vale la pena señalar, sin embargo...
... que si hash la contraseña del lado del cliente antes de enviarla, entonces el hash es la contraseña, y la contraseña original se vuelve irrelevante. Un atacante solo necesita interceptar el hash para hacerse pasar por el usuario, y si ese hash se almacena sin modificar en el servidor, entonces el servidor está almacenando la contraseña verdadera (el hash) en texto plano.

Así que su seguridad es ahora peorporque decidiste agregar tus propias mejoras a lo que anteriormente era un esquema de confianza.

 62
Author: tylerl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-17 13:14:46

La implementación de SHA-256 de Forge es rápida y confiable.

Para ejecutar pruebas en varias implementaciones de JavaScript SHA-256, vaya a http://brillout.github.io/test-javascript-hash-implementations/.

Los resultados en mi máquina sugieren que forge es la implementación más rápida y también considerablemente más rápida que la Stanford Javascript Crypto Library (sjcl) mencionada en la respuesta aceptada.

Forge tiene 256 KB de tamaño, pero extrayendo el código relacionado con SHA-256 reduce el tamaño a 4.5 KB, ver https://github.com/brillout/forge-sha256

 11
Author: brillout,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-22 19:13:12

No, no hay forma de usar JavaScript del navegador para mejorar la seguridad de las contraseñas. Te recomiendo encarecidamente que leas este artículo. En su caso, el mayor problema es el problema del huevo de gallina:

¿Cuál es el "problema del huevo de gallina" con la entrega de criptografía Javascript?

Si no confía en la red para entregar una contraseña, o, peor aún, no confía en el servidor para no guardar secretos de usuario, no puede confiar en ellos para entregar código de seguridad. El mismo atacante que fue olfatear contraseñas o leer diarios antes de introducir criptomonedas es simplemente secuestrar código criptográfico después de hacerlo.

[...]

¿Por qué no puedo usar TLS/SSL para entregar el código criptográfico Javascript?

Puedes. Es más difícil de lo que parece, pero transmite de forma segura Javascript crypto a un navegador utilizando SSL. El problema es que, habiendo establecido un canal seguro con SSL, ya no necesita criptografía Javascript; tiene criptografía "real".

Que conduce a esto:

El problema con ejecutar código criptográfico en Javascript es que prácticamente cualquier función de la que dependa el cripto podría ser anulada silenciosamente por cualquier pieza de contenido utilizada para construir la página de alojamiento. La criptoseguridad podría deshacerse al principio del proceso (generando números aleatorios falsos, o manipulando las constantes y parámetros utilizados por los algoritmos), o más tarde (devolviendo el material clave a un atacante), o --- en el escenario más probable - - - por omitiendo el crypto completamente.

No hay una forma confiable para que cualquier pieza de código Javascript verifique su entorno de ejecución. Javascript crypto code no puede preguntar, " ¿estoy realmente tratando con un generador de números aleatorios, o con algún facsímil de uno proporcionado por un atacante? Y ciertamente no puede afirmar que "a nadie se le permite hacer nada con este cripto secreto excepto en formas que yo, el autor, apruebo". Estas son dos propiedades que a menudo se proporcionan en otros entornos que usan cripto, y son imposibles en Javascript.

Básicamente el problema es este:

  • Sus clientes no confían en sus servidores, por lo que quieren agregar código de seguridad adicional.
  • Ese código de seguridad es entregado por sus servidores (en los que no confían).

O bien,

  • Sus clientes no confían en SSL, por lo que quieren que use un código de seguridad adicional.
  • Ese código de seguridad se entrega a través de SSL.

Nota: Además, SHA-256 no es adecuado para esto, ya que es muy fácil usar contraseñas de fuerza bruta sin sal no iteradas. Si usted decide hacer esto de todos modos, busque una aplicación de bcrypt, scrypt o PBKDF2.

 8
Author: Brendan Long,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-04 16:29:28

Encontré esta implementación muy fácil de usar. También tiene una generosa licencia de estilo BSD:

JsSHA: https://github.com/Caligatio/jsSHA

Necesitaba una forma rápida de obtener la representación de cadena hexadecimal de un hash SHA-256. Solo tomó 3 líneas:

var sha256 = new jsSHA('SHA-256', 'TEXT');
sha256.update(some_string_variable_to_hash);
var hash = sha256.getHash("HEX");
 7
Author: cobbzilla,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-02 00:28:05

On https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest Encontré este fragmento que usa el módulo js interno:

async function sha256(message) {
    // encode as UTF-8
    const msgBuffer = new TextEncoder('utf-8').encode(message);                    

    // hash the message
    const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);

    // convert ArrayBuffer to Array
    const hashArray = Array.from(new Uint8Array(hashBuffer));

    // convert bytes to hex string                  
    const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('');
    return hashHex;
}
 6
Author: Vitaly Zdanevich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-09 05:05:15

Para aquellos interesados, este es el código para crear hash SHA-256 usando sjcl:

import sjcl from 'sjcl'

const myString = 'Hello'
const myBitArray = sjcl.hash.sha256.hash(myString)
const myHash = sjcl.codec.hex.fromBits(myBitArray)
 3
Author: Danny Sullivan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-12 01:37:39

Además de la biblioteca de Stanford que Tylerl mencionó. Encontré jsrsasign muy útil (repositorio de Github aquí: https://github.com/kjur/jsrsasign ). No se exactamente lo confiable que es, pero he utilizado su API de SHA256, Base64, RSA, x509, etc. y funciona bastante bien. De hecho, también incluye la Stanford lib.

Si todo lo que quieres hacer es SHA256, jsrsasign podría ser una exageración. Pero si tiene otras necesidades en el área relacionada, creo que es una buena opción.

 1
Author: Faraway,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-11 22:29:03