web-dev-qa-db-fra.com

Comment faire le hachage côté client du mot de passe en utilisant BCrypt?

Je migre une ancienne application qui utilisait le hachage MD5 vers Spring Security avec l'encodage BCrypt des mots de passe. Je veux encoder le mot de passe sur la nouvelle page de création d'utilisateur, changer la page de mot de passe et sur la page de connexion avant de l'envoyer au réseau.

Je sais que HTTPS peut résoudre le problème, mais je suis toujours invité à coder le mot de passe avant de l'envoyer sur le réseau conformément à nos directives organisationnelles.

Quelle pourrait être la meilleure solution possible pour hacher les mots de passe en utilisant JavaScript?

Juste pour l'expliquer davantage, j'utilise l'API JCryption pour crypter le mot de passe en utilisant AES, donc la valeur transmise sur le réseau est AES(SHA1(MD5(plain password))) maintenant je veux remplacer MD5 avec Bcrypt uniquement. Le reste des choses reste inchangé. Cette approche fonctionnera-t-elle contre "Man in the middle attack"?

18
Amit

bcrypt n'est pas destiné à ce type de hachage côté client

Une propriété clé de bcrypt est que, lorsqu'elle est exécutée deux fois indépendantes avec le même texte en clair, la plupart des implémentations produisent des hachages différents. Cela est dû à l'utilisation d'un sel, qui est conçu pour rendre difficile de voir si deux utilisateurs différents ont le même mot de passe.

En revanche, les formulaires de connexion doivent recevoir les mêmes données à chaque fois. Après tout, comment pourriez-vous vérifier que le mot de passe que l'utilisateur a tapé aujourd'hui est le même que celui qu'il a tapé hier?

Donc, vous avez un algorithme conçu pour produire des données différentes à chaque fois, et vous les alimentez dans une application qui doit vérifier que les données sont bien les identique à chaque fois. C'est probablement une indication que l'algorithme n'est pas utilisé comme prévu.

Ce que vous devriez idéalement faire est en utilisant bcrypt pour hacher les mots de passe sur le serveur. C'est pour cela que bcrypt a été conçu: protéger les mots de passe des utilisateurs pendant les périodes où le texte en clair n'est pas en mémoire, ce qui est de loin l'état le plus courant (par exemple, les vidages de base de données ne révéleraient que le mot de passe haché, pas le texte en clair, s'il est correctement mis en œuvre).

Personnellement, je vois également une certaine valeur dans le hachage côté client, car cela aide à protéger contre les attaquants qui peuvent flairer le trafic (ou qui ont accès au serveur). Cependant, je ne connais pas de moyen de rendre le hachage côté client aussi sécurisé que bcrypt côté serveur - c'est pourquoi vous devriez toujours utiliser bcrypt côté serveur.

Si vous devez utiliser bcrypt côté client, utilisez un sel statique

Si vous allez utiliser bcrypt pour le hachage côté client d'un formulaire de connexion et que vous souhaitez qu'il remplace le MD5, vous devez utiliser un sel statique. Surtout si vous le faites passer par SHA1, car cela réduirait le sel bcrypt ainsi que les données hachées elles-mêmes.

Cela brise bien sûr plusieurs hypothèses de conception de bcrypt (comme toujours utiliser un sel aléatoire).

Je recommanderais personnellement d'utiliser le nom d'utilisateur comme sel (de sorte qu'il est difficile de dire si deux utilisateurs différents ont le même mot de passe); cependant, je ne connais aucune recherche sur le salage dans ce contexte.

AES (ou tout chiffrement symétrique) est également inutile ici

Gardez à l'esprit que AES est un algorithme symétrique, ce qui signifie que vous avez besoin de la même clé pour déchiffrer et pour chiffrer les données.

Qu'est-ce que cela signifie pour toi? Eh bien, vous avez probablement votre clé de cryptage dans la source JavaScript, qui est servie à tout client qui visite votre page de connexion. AES est un chiffrement symétrique, donc votre clé de chiffrement (qui est identique à la clé de déchiffrement) doit rester confidentielle. En d'autres termes, votre clé privée est connue du monde - elle n'offre en fait aucune sécurité à ce stade.

Ce que vous devriez utiliser à la place est cryptographie à clé publique, comme PGP ou HTTPS (techniquement, HTTPS utilise une approche hybride). Sérieusement, tilisez simplement HTTPS, à moins que votre organisation refuse de vous laisser un certificat SSL, pour une raison quelconque. Gardez à l'esprit que PGP ne protègera pas vraiment contre les attaques MITM actives, mais qu'il protégerait au moins contre les écoutes.

12
Ethan Kaminski

Je sais que HTTPS peut résoudre le problème, mais je suis toujours invité à coder le mot de passe avant de l'envoyer sur le réseau conformément à nos directives organisationnelles.

Ceci définit vraiment votre situation.

Fondamentalement, vous avez une solution simple que vous devez utiliser de toute façon (utilisez HTTPS), ne serait-ce que parce que sans HTTPS, un attaquant actif pourrait détourner la connexion après l'étape d'authentification, indépendamment de tout "encodage" et hachage que vous utilisez pour le mot de passe (un attaquant qui est en position de faire une attaque Man-in-the-Middle réussira indépendamment de combien vous dansez rituellement avec les fonctions de hachage et le cryptage). Ensuite, vous avez également une ligne directrice à la fois idiote et administrativement inévitable. Votre problème est alors: comment pouvez-vous faire les choses correctement, tout en respectant la "directive"?

Notez que la directive n'a pas beaucoup de sens à plusieurs niveaux. Non seulement le manque de SSL rend le protocole vulnérable à Hijack; mais aussi tout type de "codage" ne fait rien de bon contre les attaquants passifs non plus. La raison en est que si le protocole est "le client affiche le mot de passe" codé "", alors une écoute passive passera simplement en revue ce "mot de passe codé" et l'enverra lui-même - ainsi, ce type de codage n'améliore en fait la sécurité d'aucune manière. façon. Cela fait juste que certaines personnes se sentent plus sécurisées car elles comprennent la cryptographie comme une sorte de sauce barbecue ("plus nous saupoudrons partout, mieux c'est").

Ce que je suggère, c'est que vous fassiez ce qui suit:

  1. Tout d'abord, essayez de vendre l'idée que "HTTPS" incarne le "codage". En d'autres termes, en envoyant le mot de passe à l'intérieur d'un tunnel SSL, vous respectez déjà la directive, car le mot de passe est dûment codé (et, vraiment, crypté ), ainsi que le reste des données.

  2. Si l'infestation de stupidité est plus grave et qu'un auditeur (appelons-le Bob) continue de se plaindre de votre manque de "codage", essayez d'appliquer un codage réversible côté client. Par exemple. avant d'envoyer le mot de passe, appliquez Base64 . Cela signifie que si le mot de passe est "bobsucks", ce qui sera envoyé (dans le SSL, bien sûr) sera "Ym9ic3Vja3M =", et Bob sera plus heureux, car la dernière chaîne est évidemment beaucoup plus sûr.

Le point important ici est que, puisque l'exigence n'a pas de sens, la solution n'aura pas beaucoup de sens non plus.

45
Tom Leek

Vous n'avez aucune sécurité sans authentification

Juste pour l'expliquer davantage, j'utilise l'API JCryption pour crypter le mot de passe en utilisant AES, donc la valeur transmise sur le réseau est AES (SHA1 (MD5 (mot de passe ordinaire))) maintenant je veux remplacer MD5 par Bcrypt uniquement. Le reste des choses reste inchangé. Cette approche fonctionne même contre "Man in the middle attack".

Non, ce n'est pas le cas. Je ne peux pas exprimer cela assez fortement. Maintenant, je ne peux pas vous convaincre d'utiliser https (vous n'avez peut-être même pas le choix) mais j'espère que je peux vous convaincre que c'est absolument incertain et toute croyance que vous en avez en fournissant une certaine sécurité est incorrecte. Si vous êtes forcé d'avancer sans utiliser TLS/SSL, vous pouvez au moins indiquer très clairement à toutes les personnes impliquées que le système est vulnérable et doit être décrit comme "facilement contournable, se sentant bien en sécurité". Un script kiddie exécutant un hotspot MITM sur votre starbucks local pourrait usurper vos utilisateurs et voler des informations d'identification ou des sessions de piratage.Ce n'est donc rien qui nécessite des compétences sophistiquées ou des attaques complexes.

Si le canal de communication n'est pas sécurisé, vous ne devez pas vous attendre à ce que le code que vous envoyez soit le code qui est réellement exécuté par le client. Il y a une raison pour laquelle on l'appelle https (http sécurisé) et pas seulement httpe (http crypté), la sécurité est plus qu'un simple cryptage. La communication par chiffrement sans authentification est inutile.

Quelques réflexions:

  • Sans https, comment vos utilisateurs savent-ils même qu'ils sont sur votre page de connexion?
  • Comment savez-vous qu'un attaquant n'a pas modifié la page de connexion envoyée à l'utilisateur pour lui envoyer une copie en clair des informations d'identification avant de les crypter et de vous les envoyer?
  • Vous essayez de chiffrer le double hachage du mot de passe, comment allez-vous transmettre la clé de chiffrement en toute sécurité?

Et si je fais ma propre authentification personnalisée en plus du cryptage

Ce n'est pas aussi simple que cela. L'amorçage d'un canal sécurisé sur un canal non sécurisé n'est pas un problème trivial. En théorie, vous pourriez créer un protocole personnalisé qui reproduit tous les aspects de https, y compris la négociation de protocole, l'authentification du serveur, l'infrastructure de clé publique, l'échange de clés, le chiffrement, l'intégrité et la révocation des messages (et je suis sûr que j'ai oublié beaucoup plus). Une fois que vous avez terminé, ce serait tout aussi grand et complexe que TLS. Supposons également qu'il ait moins de défauts que n'importe quelle implémentation TLS et que vous puissiez le faire en moins de quelques années, vous auriez toujours un problème presque impossible. Comment allez-vous faire parvenir ces composants côté client au client? "Oh bien sûr, demandez au client de le télécharger en toute sécurité ... euh attendez". Si l'amorçage d'une communication sécurisée sur un canal non sécurisé semble facile, alors honnêtement, vous n'avez pas regardé assez profondément, c'est des tortues tout le long.

Maintenant, laissez-moi être clair, TLS a beaucoup de problèmes et le système CA a aussi beaucoup de problèmes. Je ne vais certainement pas prétendre que c'est parfait, mais la communication sécurisée est un problème de poulet et d'œufs tel que c'est la meilleure solution que nous ayons.

Le hachage côté client peut être effectué via https

D'après votre formulation, il semble que vous considériez la question comme "hachage côté client OR hachage côté serveur sur https" mais j'espère que vous pouvez voir que c'est une erreur. Vous avez besoin de https quelle que soit la façon dont vous le ferez. authentifier vos utilisateurs. Donc, si vous acceptez que vous avez besoin de https, la question devient "Pourquoi ou quand est-il judicieux d'utiliser le hachage côté client (sur https) au lieu du hachage côté serveur (sur https)? Dans la plupart des cas ce ne serait pas le cas. Le hachage côté client est plus complexe et pas plus sécurisé, mais il a un avantage: le serveur n'a aucune connaissance du mot de passe, ce qui n'est pas le cas du hachage côté serveur. Dans certains scénarios, vous vous voulez (le serveur) être déniable. Vous ne pouvez pas perdre une clé que vous n'avez pas et vous ne pouvez pas être obligé de déchiffrer les fichiers d'un client s'il ne vous a jamais donné la clé de déchiffrement. Il existe donc des scénarios où il peut être une exigence obligatoire mais elle doit faire partie de la conception du projet et non une décision arbitraire. Si vous avez des questions spécifiques sur comment gérer les scénarios de connaissance zéro, il serait préférable de poser une nouvelle question.

25
Gerald Davis

La meilleure solution est: ne le faites pas.

Si vous envoyez les mots de passe via HTTPS, leur hachage n'offre aucune sécurité supplémentaire.

Si vous envoyez les mots de passe via HTTP simple, un attaquant peut récupérer le mot de passe haché et l'utiliser pour se connecter; Alternativement, ils peuvent altérer le JavaScript pour leur envoyer le mot de passe avant le hachage. Dans les deux cas, le hachage du mot de passe n'offre aucune sécurité.

9
Mark

Puisque vous semblez déterminé à mettre en œuvre cette directive, je répondrai directement à votre question. Mais comprenez que BCrypt et MD5 sont très différents. BCrypt fait délibérément un travail considérable, tandis que MD5 en fait beaucoup moins, vous devrez donc tenir vos promesses:

<!-- 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>

Je vous exhorte à prendre en considération les conseils avisés dans les autres réponses. Les scénarios où cette directive ajoute de la valeur sont rares, alors demandez-vous: Pourquoi investir un travail double dans une infrastructure redondante qui n'ajoute aucune sécurité et ralentit l'expérience utilisateur?

Références:

  1. Le cryptage de transport protège tous les secrets .

  2. L'envoi d'un hachage équivaut à l'envoi d'un mot de passe , et la génération d'un hachage sécurisé est nécessairement lente .

  3. La résistance en force brute de bcrypt contre MD5 pour le hachage de mot de passe? et résultats des tests de performance de l'algorithme de hachage .

5
bishop