web-dev-qa-db-fra.com

Existe-t-il des implémentations javascript SHA-256 généralement considérées comme fiables?

Je suis en train d'écrire un login pour un forum, et j'ai besoin de hacher le mot de passe côté client en javascript avant de l'envoyer au serveur. Je n'arrive pas à déterminer quelle implémentation de SHA-256 je peux réellement faire confiance. Je m'attendais à ce qu'il y ait une sorte de script faisant autorité que tout le monde utilisait, mais je découvre une multitude de projets différents, tous avec leurs propres implémentations.

Je réalise que l'utilisation de la crypto d'autres personnes est toujours un acte de foi, à moins que vous ne soyez qualifié pour l'examiner vous-même et qu'il n'existe pas de définition universelle de "digne de confiance", mais cela semble être assez courant et assez important pour qu'il en soit de même de consensus sur ce qu'il faut utiliser. Suis-je juste naïf?

Edit car cela est souvent mentionné dans les commentaires: Oui, nous faisons à nouveau un hachage plus strict du côté serveur. Le hachage côté client n'est pas le résultat final que nous sauvegardons dans la base de données. Le hachage côté client est dû au fait que le client humain le demande. Ils n’ont pas donné de raison particulière, probablement parce qu’ils aiment trop.

59
jono

La Stanford JS Crypto Library contient une implémentation de SHA-256. Bien que la cryptographie dans JS ne soit pas vraiment une entreprise aussi bien contrôlée que celle d’autres plates-formes d’implémentation, celle-ci est au moins partiellement développée par, et dans une certaine mesure, parrainée par Dan Boneh , qui est un acteur bien établi Nom de confiance en cryptographie, ce qui signifie que le projet est supervisé par quelqu'un qui sait réellement ce qu'il fait. Le projet est également soutenu par le NSF .

Cela vaut la peine de préciser, cependant ...
... que si vous hachez le mot de passe côté client avant de le soumettre, alors hash est le mot de passe, et le mot de passe d'origine devient inutile. Un attaquant n'a qu'à intercepter le hachage pour emprunter l'identité de l'utilisateur. Si ce hachage est stocké non modifié sur le serveur, , alors le serveur stocke le true mot de passe (le hachage) en texte brut.

Donc, votre sécurité est maintenant pire parce que vous avez décidé d'ajouter vos propres améliorations à ce qui était auparavant un schéma de confiance.

77
tylerl

L'implémentation SHA-256 de Forge est rapide et fiable.

Pour exécuter des tests sur plusieurs implémentations JavaScript SHA-256, accédez à http://brillout.github.io/test-javascript-hash-implementations/ .

Les résultats sur ma machine suggèrent que forge soit l’implémentation la plus rapide et considérablement plus rapide que la bibliothèque de cryptographie Javascript de Stanford (sjcl) mentionnée dans la réponse acceptée.

Forge a une taille de 256 Ko, mais l'extraction du code associé à SHA-256 réduit la taille à 4,5 Ko, voir https://github.com/brillout/forge-sha256

13
brillout

Sur https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest J'ai trouvé ce fragment de code qui utilise le module js interne:

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;
}

Notez que crypto.subtle est uniquement disponible sur https ou localhost - par exemple, pour votre développement local avec python3 -m http.server, vous devez ajouter cette ligne à votre /etc/hosts: 0.0.0.0 localhost

Redémarrez - et vous pouvez ouvrir localhost:8000 avec crypto.subtle actif.

13
Vitaly Zdanevich

Non, il n'y a aucun moyen d'utiliser le navigateur JavaScript pour améliorer la sécurité des mots de passe. Je vous recommande fortement de lire cet article . Dans votre cas, le plus gros problème est le problème poulet-œuf:

Quel est le "problème œuf-poule" avec la fourniture de cryptographie Javascript?

Si vous ne faites pas confiance au réseau pour fournir un mot de passe ou, pire, ne faites pas confiance au serveur pour ne pas garder les secrets de l'utilisateur, vous ne pouvez pas lui faire confiance pour lui donner le code de sécurité. Le même attaquant qui flairait des mots de passe ou lisait des journaux avant de vous présenter crypto est simplement en train de détourner un code crypté après vous.

[...]

Pourquoi ne puis-je pas utiliser TLS/SSL pour transmettre le code crypté Javascript?

Vous pouvez. C'est plus difficile que ça en a l'air, mais vous transmettez en toute sécurité le cryptage Javascript à un navigateur utilisant SSL. Le problème est que, après avoir établi un canal sécurisé avec SSL, vous n’avez plus besoin de la cryptographie Javascript; vous avez une "vraie" cryptographie.

Ce qui mène à ceci:

Le problème avec l'exécution de code crypté en Javascript est que pratiquement toute fonction dont dépend le cryptage peut être remplacée en silence par tout élément de contenu utilisé pour créer la page d'hébergement. La sécurité cryptographique pourrait être annulée tôt dans le processus (en générant de faux nombres aléatoires, ou en altérant les constantes et les paramètres utilisés par les algorithmes), ou plus tard (en renvoyant du matériel clé à un attaquant), ou --- dans la plupart des cas. scénario probable --- en contournant entièrement le crypto.

Il n’existe aucun moyen fiable permettant à un élément de code Javascript de vérifier son environnement d’exécution. Le code cryptographique Javascript ne peut pas demander: "est-ce que je traite réellement avec un générateur de nombres aléatoires, ou avec un fac-similé d'un générateur fourni par un attaquant?" Et il ne peut certainement pas affirmer "personne n'est autorisé à faire quoi que ce soit avec ce crypto secret sauf d'une manière que moi, l'auteur, j'approuve". Ce sont deux propriétés qui sont souvent fournies dans d'autres environnements utilisant la cryptographie et qui sont impossibles en Javascript.

Fondamentalement, le problème est le suivant:

  • Vos clients ne font pas confiance à vos serveurs, ils veulent donc ajouter un code de sécurité supplémentaire.
  • Ce code de sécurité est fourni par vos serveurs (ceux auxquels ils ne font pas confiance).

Ou bien,

  • Vos clients ne font pas confiance à SSL, ils veulent donc que vous utilisiez un code de sécurité supplémentaire.
  • Ce code de sécurité est livré via SSL.

Remarque: SHA-256 ne convient pas non plus à cet usage, car il est si facile de utiliser des mots de passe brutaux non itérés avec force . Si vous décidez néanmoins de le faire, recherchez une implémentation de bcrypt , scrypt ou PBKDF2 .

10
Brendan Long

J'ai trouvé cette implémentation très facile à utiliser. Possède également une licence généreuse de style BSD:

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

J'avais besoin d'un moyen rapide pour obtenir la représentation hexadécimal d'un hachage SHA-256. Il n'a fallu que 3 lignes:

var sha256 = new jsSHA('SHA-256', 'TEXT');
sha256.update(some_string_variable_to_hash);
var hash = sha256.getHash("HEX");
6
cobbzilla

Pour les intéressés, il s'agit d'un code permettant de créer un hachage SHA-256 à l'aide de sjcl:

import sjcl from 'sjcl'

const myString = 'Hello'
const myBitArray = sjcl.hash.sha256.hash(myString)
const myHash = sjcl.codec.hex.fromBits(myBitArray)
5
Danny Sullivan

Outre la librairie de Stanford mentionnée par Tylerl. J'ai trouvé jsrsasign très utile (rapport Github ici: https://github.com/kjur/jsrsasign ). Je ne sais pas à quel point c'est digne de confiance, mais j'ai utilisé ses API SHA256, Base64, RSA, x509, etc., et cela fonctionne plutôt bien. En fait, cela inclut également la bibliothèque de Stanford.

Si tout ce que vous voulez faire est SHA256, jsrsasign pourrait être une overkill. Mais si vous avez d'autres besoins dans le même domaine, je pense que c'est un bon choix. 

0
Faraway