Nous avons parlé du hachage et du salage des mots de passe en classe aujourd'hui. Notre professeur avait une compréhension très différente du cas d'utilisation des sels du mien et a dit que vous ne pourriez pas du tout stocker le sel et vérifier simplement chaque tentative de connexion avec tous les sels possibles et autoriser si une correspond.
Je ne vois vraiment aucun point à cela, car maintenant mon service est beaucoup plus vulnérable aux attaques par force brute (envoyer un mot de passe, le serveur en vérifie plusieurs), mais je suppose que c'est un peu plus sûr pour les attaques de dictionnaire pur contre le mot de passe haché .
Y a-t-il donc un cas d'utilisation où les gens feraient réellement cela?
Ne pas stocker le sel est un mauvais conseil.
Le but principal d'un sel est que chaque mot de passe utilisateur doit être attaqué individuellement.
Si vous ne stockez pas le sel, comme vous l'avez dit, vous devez essayer chaque combinaison de sel afin de valider le mot de passe. Si vous devez vérifier chaque combinaison de sel, cela signifie que le sel ne peut pas être trop long (vous avez mentionné 12 bits dans un commentaire). Si le sel n'est pas long, cela signifie que le sel sera répété pour de nombreux utilisateurs. S'il est répété pour de nombreux utilisateurs, cela signifie que l'attaquant pourra attaquer plusieurs utilisateurs en même temps, ce qui lui fera gagner du temps.
En faisant cela, vous déjouez presque complètement le but d'utiliser un sel.
De Wikipédia:
Un poivre peut être ajouté à un mot de passe en plus d'une valeur de sel. Un poivre joue un rôle similaire à un sel, cependant, alors qu'un sel est généralement stocké à côté de la valeur hachée, pour que quelque chose soit défini comme un poivre, il devrait répondre à l'un des critères suivants qui le définissent comme un `` secret '' plus soigneusement caché. que la valeur du sel:
- Le poivron est détenu séparément de la valeur à hacher
- Le poivre est généré de manière aléatoire pour chaque valeur à hacher (dans un ensemble limité de valeurs) et n'est jamais stocké. Lorsque les données sont testées par rapport à une valeur hachée pour une correspondance, cela se fait en itérant à travers l'ensemble de valeurs valides pour le poivre, et chacune à son tour est ajoutée aux données à tester (généralement en les suffixant aux données), avant l'exécution de la fonction de hachage cryptographique sur la valeur combinée.
L'avantage d'un poivre est qu'un attaquant doit maintenant deviner jusqu'au nombre de permutations possibles d'une valeur de poivre pour chaque entrée de texte en clair.
N'oubliez pas qu'un sel est une atténuation efficace des hachages précalculés et qu'il fait passer un attaquant longtemps à attaquer un ensemble de hachages. Cependant, si un seul hachage est préoccupant et qu'aucun hachage précalculé ne doit être utilisé, un sel n'augmente pas la durée de l'attaque. Un Pepper oblige cependant l'attaquant à utiliser plusieurs suppositions pour chaque mot de passe en clair, même pour un seul hachage.
De cette façon, un poivre est similaire à étirement des touches .
Mon observation personnelle est que la plupart des implémentations préfèrent l'étirement des clés aux poivrons. Je n'ai pas de référence pour cela, donc les lecteurs peuvent fournir des références à l'appui ou dissidentes dans les commentaires. Les gens ont tendance à préférer l'étirement des clés car il présente un coût de performance et un avantage de sécurité connus et attendus. Pour calculer le Nième tour d'un hachage, N hachages doivent être calculés. Cependant, avec un piment, seul le nombre de tentatives attendu peut être calculé. Considérons un poivre de 1 octet, l'attaquant aurait besoin de 256 suppositions pour deviner toutes les combinaisons possibles, mais le valeur attendue est 128, et l'attaquant pourrait (en moyenne 1/256 fois) deviner la valeur sur le premier essai.
L'étirement des touches est efficace car vous pouvez définir le nombre de tours en fonction de la durée pendant laquelle le calcul d'un hachage doit prendre. Supposons que vous vouliez qu'une seule vérification prenne une demi-seconde sur le matériel actuel, vous augmentez simplement les tours jusqu'à ce que cela se produise.
Avec un piment, car vous devez deviner plusieurs valeurs pour chaque mot de passe, la taille d'un piment doit être inversement liée au nombre de tours afin de maintenir la constante de temps de calcul.
Le meilleur conseil pour les implémentations de mot de passe/hachage est d'utiliser des méthodologies bien connues et des bibliothèques testées. Vous devez utiliser bcrypt ou pbkdf2 avec un sel unique et plusieurs tours. Ces algorithmes ont généralement des implémentations bien connues dans de nombreux langages et frameworks. Si vous trouvez une bibliothèque bien connue et testée qui comprend un poivre, en plus des sels et de l'étirement des clés, cela peut valoir la peine de l'utiliser, mais l'avantage supplémentaire l'emporte souvent sur les coûts de performance.
Contexte: Vous devez utiliser un hachage de mot de passe lent. (c.-à-d. bcrypt) Par `` lent '', je veux dire cher en calcul, prenant plus de 100 ms (sur votre matériel) avec protection DoS * pour tester un seul mot de passe. Il s'agit d'augmenter la puissance de traitement nécessaire (sur le matériel de l'attaquant) pour trouver le mot de passe par force brute, en cas de vol du hachage.
Le sel unique par utilisateur est fortement recommandé. (dans le cas de bcrypt, il est généré automatiquement) Le sel doit être hautement unique (c'est-à-dire long et aléatoire), mais pas secret . L'utilisation de sel unique signifie qu'un attaquant devrait exécuter un Job de force brute distinct pour chaque utilisateur.
S'il n'y avait "pas de sel", l'attaquant pourrait instantanément utiliser un Rainbow Table et aucune force brute du tout.
Si vous utilisez uniquement un "sel partagé", un attaquant pourrait casser des mots de passe pour tous les utilisateurs avec un travail de force brute unique. (pas aussi rapide qu'une table arc-en-ciel mais toujours beaucoup plus facile qu'un job de force brute séparé pour chacun)
Réponse: Si vous ne "stockez" pas le sel ("force brute le hachage à l'exécution" comme le suggère votre professeur)
Cela irait totalement à l'encontre de l'objectif de Salt , paralyse gravement les avantages d'un hachage lent. C'est une erreur de conception majeure de la part de votre professeur. Fondamentalement, il est roulant son propre schéma de stockage de mot de passe, où il devrait utiliser l'algorithme bien vérifié bcrypt (ou scrypt ou PBKDF2 ) tel qu'il était destiné à être utilisé.
* Comme @ Navin commenté, ce serait un vecteur d'attaque DoS potentiel. Une solution consiste à limiter le nombre de tentatives horaires par IP et par nom d'utilisateur. Il est également possible que vous réduisiez la "lenteur" de votre hachage pour ne prendre que 10 ms. Ce n'est pas aussi bon que 100 ms dans une perspective de "hachage volé", mais toujours bien mieux que les "microsecondes".
Votre professeur n'a pas raison. Le but d'un sel est d'augmenter l'entropie des mots de passe hachés pour empêcher toute sorte d'attaque de pré-calcul sur eux ainsi que d'empêcher le même mot de passe de différents utilisateurs d'avoir la même valeur hachée.
Pouvoir essayer toutes les valeurs de sel possibles signifie que vous devez avoir une très faible quantité d'entropie dans le sel, ce qui signifie qu'un pré-calcul via les tables Rainbow est possible.
Vous pouvez utiliser le sel de cette façon. Ce serait une sorte de processus d'étirement du hachage. En règle générale, vous étirez un hachage en répétant l'algorithme plusieurs milliers de fois, ce qui ralentit les attaquants et les utilisateurs de 1000 fois, mais les utilisateurs ne sont généralement pas gênés par le ralentissement. L'utilisation d'un sel de cette manière aurait pour effet de faire un algorithme d'étirement de hachage en le répétant pour de nombreux hachages inconnus.
Cependant, c'est une approche extrêmement inhabituelle. Les méthodes traditionnelles de salage font ce que les sels sont censés faire beaucoup mieux (faites en sorte que personne ne puisse précalculer une table de mots de passe). Les méthodes traditionnelles de l'étirement du hachage font ce que l'étirement du hachage est censé faire beaucoup mieux (faites en sorte que les attaquants mettent plus de temps à calculer les mots de passe). Utiliser un sel de cette façon revient à les museler ensemble. Le genre de résultat en quelque sorte fonctionne, mais les approches plus propres font les deux solutions loin mieux que la mauvaise confusion des techniques.
Plutôt que de penser au sel en termes de forçage brutal, j'aime y penser en termes de dire qu'il est impossible de dire quoi que ce soit sur un mot de passe, y compris sa relation avec d'autres mots de passe, en le regardant. Si le système n'utilise pas de salage, la recherche des mots de passe hachés de deux utilisateurs indiquerait si leurs vrais mots de passe correspondent. Si un système salé en utilisant uniquement le nom d'utilisateur mais rien d'aléatoire, temporel ou spécifique au système, regarder les mots de passe hachés d'un utilisateur sur deux machines qui utilisent la même approche indiquerait si les mots de passe de l'utilisateur sur les deux machines correspondaient. Si le système salé en utilisant l'ID système et le nom d'utilisateur, mais rien d'aléatoire ou de temporel, alors quelqu'un ayant accès à deux hachages de mot de passe différents par le même utilisateur pourrait dire si les mots de passe associés correspondent.
Le salage aléatoire a pour effet de faire en sorte qu'il n'y ait pas deux hachages utilisant le même mot de passe, même s'ils impliquent le même utilisateur sur le même système. Bien que l'on puisse obtenir un effet similaire sans stocker les sels si les tentatives de connexion devaient les forcer par brute, une telle approche limiterait la longueur pratique du sel que l'on pourrait utiliser et augmenterait ainsi la probabilité que les mots de passe utilisés dans deux contextes aient le même sel et donc être reconnaissable comme correspondant.
Que vous apporte le salage? Les attaquants ont des bases de données pré-calculées de valeurs de hachage pour les mots de passe, communs et non. S'ils capturent votre base de données et ont le hachage des mots de passe pour chaque utilisateur, il est simple de comparer leurs hachages par rapport à ces valeurs sans sel.
Avec un sel aléatoire stocké avec le mot de passe, cette méthode rapide incroyablement n'est plus possible. Mais si l'attaquant possède le sel ainsi que le hachage, il est toujours possible d'utiliser des attaques par dictionnaire pour les mots de passe faibles ou le forçage brutal pour les mots courts. Il suffit à l'attaquant d'utiliser le sel et d'essayer différents mots de passe à l'aide d'un dictionnaire ou d'une attaque par force brute.
Maintenant, disons que lorsque le mot de passe est modifié, vous le hachez avec une valeur aléatoire de 12 bits qui n'est pas stockée avec le sel qui l'est. Ensuite, chaque fois que vous vérifiez le mot de passe, vous devez essayer toutes les valeurs 4096. Sur mon ordinateur, cela prend environ 3,5 ms, donc 284 mots de passe peuvent être vérifiés chaque seconde. Un peu plus d'utilisation du processeur sur le serveur lorsque quelqu'un se connecte, mais pour quelqu'un qui essaie un dictionnaire ou des attaques par force brute, vous venez de rendre leur travail beaucoup plus difficile, même s'ils ont le hachage et le sel.
Dans la nature, nous avons une table d'utilisateurs. Une table d'utilisateurs est généralement
ID | username | salt | encrypted_password | horridly_insecure_reset_key
===========================================================================
1 | user1 | foo | 09b6d39aa22fcb8698687e1af09a3af9 | NULL
2 | user2 | bar | 6c07c60f4b02c644ea1037575eb40005 | NULL
3 | user3 | baz | 09b6d39aa22fcb8698687e1af09a3af9 | reset
Ensuite, une méthode d'authentification ressemblera à quelque chose
def authenticate(user, password)
u = User.find(user: user)
return u.encrypted_password == encrypt(password + u.salt)
end
En ayant un sel par utilisateur, il garantit que même si le mot de passe de l'utilisateur1 est connu, vous ne pouvez pas comprendre le mot de passe de l'utilisateur2 ou de l'utilisateur3 sans leur sel.
Vous vous assurez également que vous ne pouvez pas comprendre le sel en ayant un ensemble de mots de passe cryptés et en essayant quelques mots de passe cryptés.
Essentiellement, de cette façon, chaque attaque contre un utilisateur doit être lancée à partir de zéro.
Même si un attaquant a une liste d'utilisateurs et de sels, il doit toujours faire le crack contre chaque utilisateur pour voir s'il a une correspondance de mot de passe. Si vous aviez un pool de sels, ou un sel statique, je pourrais savoir que le mot de passe de user1 est mot de passe et puis juste trouver tous les mots de passe cryptés qui correspondent. Ainsi, au moins, cela les ralentit un peu plus.
Maintenant, lorsque nous examinons les sels, nous voulons réduire la réutilisation du sel. Deux sels identiques faciliteront la tâche des attaquants. Si deux personnes partagent le même sel et le même mot de passe, casser un utilisateur cassera l'autre.
Disons donc que nous n'utilisons que ces trois sels. Et nous avons 3000 utilisateurs. cela signifie que 1000 personnes ont le même sel. Si 1% d'entre eux ont un mot de passe "mot de passe", ces personnes peuvent être piratées en même temps. 10 comptes sont piratés à la fois. Parce que nous connaissons les trois sels. C'est un tronçon très facile pour attaquer 30 personnes à la fois.
Maintenant, si chaque sel est unique. Et nous savons que le mot de passe de l'utilisateur1 est un mot de passe, cela ne vous fait aucun bien. Vous n'avez encore piraté qu'un seul utilisateur. Vous devez toujours faire "ne mot de passe + sel = mot de passe crypté" pour tous les autres 2999 utilisateurs.
Une note vraiment importante.
La sécurité par l'obscurité n'est pas la sécurité. Cela ne signifie pas que vous devez publier votre tableau d'utilisateurs sur Google, car c'est idiot. Mais lorsque vous mesurez la sécurité, vous devez supposer que l'attaquant a tout. Vous ne pouvez pas dire "mais ils ne connaîtront pas le sel de l'application car ils n'ont pas le code source". Parce qu'ils pourraient. Cela ne signifie pas donner vos sels, cela signifie simplement que ce n'est pas une vraie sécurité. Supposons qu'ils aient le nom d'utilisateur et le sel, puis essayez de leur rendre plus difficile l'obtention du mot de passe.
NOTE SUPER IMPORTANTE
Le code et le tableau utilisés ici sont environ 9 000 fois trop simples pour une utilisation réelle. Le mot de passe n'est pas crypté, les sels sont trop courts, la méthode est un peu simpliste, bref faire quelque chose comme ça en production n'est pas quelque chose qui devrait être considéré comme sûr. J'ai choisi ces causes là simplement pour le point de démonstration, non pas parce qu'elles sont sécurisées.
Il semble y avoir un certain mérite dans l'idée de ne pas stocker n certain nombre contrôlé de bits du sel, qui est configuré indépendamment et est indépendant de la taille du sel.
Supposons que nous ayons des sels 32 bits. Nous pourrions choisir de ne stocker que 22 bits et d'utiliser la force brute sur les 10 autres lorsque nous nous authentifierons. L'effet est comme si plus de tours étaient ajoutés à la fonction de hachage. Pas tellement que l'authentification légitime est affectée, mais suffisamment pour augmenter la difficulté du craquage par force brute.
L'année prochaine, les machines s'accélèrent. Nous parcourons donc la base de données de mots de passe et supprimons un peu de chaque sel: maintenant, nous ne stockons que 21 bits et devons forcer par 11.
C'est comme si nous doublions la force de hachage, mais sans interrompre le remplacement de l'algorithme et amener les utilisateurs à re-hacher leurs mots de passe (ce qui est laissé à la politique d'expiration des mots de passe).
Cette approche de "rejet progressif du sel" pourrait prolonger la durée de vie utile des fonctions de hachage.
Cependant, ces types d'approches ralentissent l'authentification légitime et l'attaque par force brute d'un facteur égal, donc au mieux, elles fournissent une couche de sécurité mineure. Nous devons nous concentrer sur les améliorations qui n'apportent qu'une quantité constante de temps supplémentaire à une utilisation légitime, tout en multipliant la difficulté de craquage. Bien sûr, une amélioration qui a cette propriété augmente la quantité d'entropie dans la phrase de mot de passe! Chaque bit d'entropie ajouté au mot de passe ajoute un coût constant aux utilisateurs légitimes, tout en doublant l'effort de craquage par force brute. Un mot de passe de longueur N prend O(N) pour le hachage (et le type), mais O (2 ** N) pour la force brute. L'ajout de 12 bits d'entropie à un mot de passe bat la dissimulation de 12 bits de sel.