web-dev-qa-db-fra.com

Comment fonctionne le stockage des mots de passe de hachage?

Dans les applications réseau habituelles, qui utilisent le hachage de mot de passe, le mot de passe utilisateur est-il haché côté client avant de l'envoyer au serveur, ou est-il envoyé sans hachage comme cryptage du mot de passe en texte brut au serveur?

La principale question que j'ai est de savoir si un attaquant découvre les mots de passe hachés, alors pourquoi ne peut-il pas simplement envoyer du hachage au serveur pour s'authentifier en cas de hachage côté client?

27
Allahjane

Au moins en partie du hachage doit se produire côté serveur. En effet, tout ce que le client envoie au serveur accorde l'accès, donc si cette même valeur est juste stockée telle quelle sur le serveur, alors vous avez les mêmes problèmes que le stockage de mot de passe en texte clair, à savoir qu'un seul aperçu en lecture seule sur votre serveur la base de données donne tous les accès.

Dans la plupart des cas tout le hachage est effectué sur le serveur, car le client est un navigateur Web qui peut, au mieux, faire du Javascript, et Javascript n'est pas très bon pour les tâches cryptographiques. Le client envoie le mot de passe lui-même (via HTTPS bien sûr), et le serveur calcule le hachage et le compare avec la valeur de hachage stockée. L'attaquant ne peut pas simplement "passer le hachage"; il doit envoyer une valeur qui, lorsqu'elle est hachée par le serveur, donne la valeur de hachage stockée.

Si les clients sont capables de faire de la cryptographie (par exemple, un client natif lourd pour un jeu), la majeure partie du processus de hachage peut être effectuée côté client, mais il doit encore y avoir un calcul de hachage final effectué sur le serveur.

39
Thomas Pornin

Comment le hachage du mot de passe de connexion est supposé fonctionner

Notez que dans tous les extraits de code, j'exclus intentionnellement les fonctionnalités de sécurité, car je veux le garder compact. Ne vous fiez à ces extraits de code pour rien.

Dans les applications réseau habituelles, qui utilisent le hachage de mot de passe, le mot de passe utilisateur est-il haché côté client avant de l'envoyer au serveur ou est-il envoyé sans hachage comme cryptage du mot de passe en texte brut au serveur?

Non, c'est haché côté serveur. Vous envoyez le mot de passe en texte brut ou via HTTPS au serveur. Le serveur générera alors un hachage pour le mot de passe, comme ceci:

public void RegisterAccount(string username, string password, string email)
{
     if (!Database.EmailExists(email) && !Database.UsernameExists(username))
     {
         Database.AddNewUser(username, Hash.GenerateHash(password), email);
     }
}

Supposons que Database.AddNewUser(string, string, string); insère le nom d'utilisateur, le mot de passe haché et l'e-mail dans la base de données. Le hachage est généré en fonction du mot de passe.

Disons que vous avez entré "ne me piratez pas s'il vous plaît" comme mot de passe. bcrypt transformera cela en $2a$08$BOHyNdXAVkWOUgPG/hvsjew7ZpngqJIgueY6m76xd4y3UllXUZLBy, ou une autre variante basée sur le sel. La base de données ressemble maintenant à ceci:

+--------------+--------------------------------------------------------------+--------------------+
|    user      |    password                                                  |       email        |
+--------------+--------------------------------------------------------------+--------------------+
| markbuffalo  | $2a$08$BOHyNdXAVkWOUgPG/hvsjew7ZpngqJIgueY6m76xd4y3UllXUZLBy |   [email protected] |
+--------------+--------------------------------------------------------------+--------------------+

Normalement, vous allez appeler la base de données pour lire le mot de passe de ce nom d'utilisateur. Une fois que vous appelez la base de données, vous allez utiliser une fonction, telle que Hash.ValidateHash(), pour voir si elle correspond. S'il correspond, vous pouvez vous connecter en utilisant ce mot de passe non haché.


Pourquoi ne pouvez-vous pas simplement passer le hachage pour vous connecter?

Vous pouvez dans certains cas très malheureux .

La principale question que j'ai est de savoir si un attaquant découvre les mots de passe hachés, alors pourquoi ne peut-il pas simplement envoyer du hachage au serveur pour s'authentifier en cas de hachage côté client?

Cela est possible, mais cela ne peut se produire que dans les cas graves d'échec massivement épique de la part des développeurs. En fait, je l'ai déjà vu et je vais vous montrer comment cela peut se produire via le code:

public void Login(string username, string password)
{
    if (Database.LoginMatches(username, password) ||
        Database.LoginMatches(username, Hash.ValidateHash(password)))
    {
        logMeIn();
    }
}

Dans l'extrait ci-dessus, la connexion souhaite vérifier si l'utilisateur possède le hachage ou le mot de passe qui sera validé dans le hachage stocké dans la base de données. Ce n'est pas la bonne façon de procéder. En fait, c'est l'un des pires échecs épiques que j'ai jamais vus de ma vie.

Avec ce code, vous pouvez simplement saisir le hachage ou le mot de passe et vous connecter. Rappelez le tableau précédent. L'une des connexions suivantes fonctionnera correctement:

  1. Login("markbuffalo", "$2a$08$BOHyNdXAVkWOUgPG/hvsjew7ZpngqJIgueY6m76xd4y3UllXUZLBy");
  2. Login("markbuffalo", @"don't hack me please");

C'est la mauvaise approche entièrement. Ce n'est pas censé arriver. À. Tout. Néanmoins, certains développeurs ont adopté cette approche pour des raisons que je ne connais pas.


Quelle est la bonne approche pour la validation du hachage?

Comme Rápli András dit, h(x) ne correspond pas à h(h(x)). L'approche droite consiste à vérifier le mot de passe entrant par rapport au hachage pour voir s'il correspond. S'ils ne correspondent pas, n'utilisez pas de OR magic (||); ne leur permettez tout simplement pas de se connecter.

24
Mark Buffalo

À votre première question:

Cela dépend de l'application. Dans la plupart des cas, le mot de passe est envoyé au serveur en texte clair (et ce n'est pas sûr si l'application utilise un protocole non chiffré, tel que HTTP). Cependant, le serveur peut stocker une valeur hachée dans la base de données. Si tel est le cas, l'application calcule la valeur de hachage du mot de passe en texte clair reçu de l'utilisateur et la compare à la valeur stockée dans la base de données.

À votre deuxième question:

Le serveur attend une entrée de mot de passe: X. L'attaquant découvre en quelque sorte h(X). S'il entrait cette valeur de hachage pour s'authentifier, la fonction de hachage serait à nouveau exécutée contre h(x), il ne pourrait donc pas entrer car h(x) ne correspond pas à h(h(x)).

3
Rápli András

Comme d'autres l'ont souligné, la manière habituelle de faire cela est que le client envoie le mot de passe en texte clair, mais sur un canal sécurisé (qui utilise un cryptage réversible, pas de hachage ), et ce mot de passe est ensuite haché côté serveur avec le même sel que le hachage stocké.

       Client      <----- Secure link ----->     Server
Cleartext password     Encrypted password    Hashed password
  1. Le client a le mot de passe en texte clair.
  2. Le client chiffre le mot de passe (via TLS)
  3. Le serveur reçoit un mot de passe chiffré, le déchiffre (via TLS)
  4. Le serveur hache le mot de passe avec le même sel que celui stocké dans la base de données pour cet utilisateur
  5. Le serveur compare le hachage calculé avec le hachage stocké.

Protection:

  • contre l'écoute clandestine (en raison de l'utilisation d'un canal sécurisé)
  • contre les attaques MITM (si la session TLS est correctement configurée, les certificats correctement vérifiés, etc.)
  • contre le vol de base de données de mots de passe

Maintenant, le problème est quand vous devez envoyer un mot de passe sur un canal qui ne fournit pas de cryptage , comme cela pourrait être le cas pour le protocole de bas niveau (pour instance PPP ou 802.1X). ​​Les choix traditionnels (pour PPP) étaient:

  • PAP : envoyer le mot de passe en texte clair, qui peut ensuite être haché côté serveur pour comparaison avec la base de données de mots de passe hachés

  • CHAP : utilisez un protocole défi-réponse et envoyez une version hachée du mot de passe (combinée avec le défi et un identifiant) sur le lien, mais cela nécessitait la serveur pour stocker le texte en clair des mots de passe

Ainsi, le premier protège contre le vol de base de données de mot de passe, mais pas contre l'écoute, tandis que la situation est inversée pour le second.

Mis à part les protocoles EAP qui mettent en place un tunnel TLS (PEAP, EAP-TTLS, EAP-TLS ...) pour sécuriser l'échange de mots de passe, il existe un protocole alternatif qui permet d'envoyer un "hachage" non réversible du mot de passe à un serveur, qui stocke également un "hachage" du mot de passe: SRP , et plus généralement "augmenté PAKE "protocoles.

1
jcaron

Une attaque basée sur le simple renvoi de données capturées (par exemple un mot de passe haché par le client) sans avoir besoin de déchiffrer les données est connue sous le nom d'attaque de "rejeu". L'atténuation standard de cette attaque consiste à inclure ce qui est connu comme un "nonce" dans les données hachées, cela peut être un nombre aléatoire fourni par le serveur ou un horodatage raisonnablement haute résolution généré par le client. Le serveur vérifiera alors que le nonce est valide ou dans une plage acceptable, et s'il est incorrect ou trop ancien, il rejettera la demande. Une discussion détaillée peut être trouvée ici Quelle est l'utilité d'un nonce client?

0
Ken