63 votes

Cryptage/hachage de mots de passe en texte clair dans la base de données

J'ai hérité de une application web dont je viens de découvrir qu'elle stocke plus de 300 000 noms d'utilisateur/mots de passe en texte clair dans une base de données SQL Server. Je réalise que c'est une Très Mauvaise Chose™.

Sachant que je devrai mettre à jour les processus d'ouverture de session et de mise à jour des mots de passe pour crypter/décrypter, et avec le moins d'impact possible sur le reste du système, quel serait le meilleur moyen de supprimer les mots de passe en texte brut de la base de données ?

Toute aide est appréciée.

Edit : Désolé si je n'ai pas été clair, je voulais demander quelle serait votre procédure pour crypter/hacher les mots de passe.

Je devrais juste :

  1. Faites une sauvegarde de la BD
  2. Mise à jour du code d'accès/mise à jour du mot de passe
  3. Après quelques heures, parcourez tous les enregistrements de la table des utilisateurs en hachant le mot de passe et en remplaçant chacun d'entre eux.
  4. Testez pour vous assurer que les utilisateurs peuvent toujours se connecter/mettre à jour leurs mots de passe.

Je pense que mon inquiétude vient plutôt du nombre d'utilisateurs et je veux m'assurer que je fais les choses correctement.

49voto

orip Points 28225

EDIT (2013) : utilisation scrypt , bcrypt o PBKDF2 dans cet ordre de préférence. Utilisez un facteur de ralentissement aussi important que possible pour votre situation. Utilisez une implémentation existante validée. Assurez-vous d'utiliser un sel approprié (bien que les bibliothèques que vous utilisez devraient s'en assurer pour vous).


Lorsque vous hacherez les mots de passe, utilisez N'UTILISEZ PAS DE MD5 SIMPLE .

Utilisez PBKDF2 ce qui signifie essentiellement l'utilisation d'un sel aléatoire pour empêcher table arc-en-ciel et en procédant à une itération (nouveau hachage) suffisante pour ralentir le hachage - pas au point que votre application prenne trop de temps, mais suffisamment pour qu'un attaquant forçant brutalement un grand nombre de mots de passe différents s'en aperçoive.

Du document :

  • Faites des itérations au moins 1000 fois, de préférence plus - chronométrez votre mise en œuvre pour voir combien d'itérations sont réalisables pour vous.
  • 8 octets (64 bits) de sel sont suffisants, et l'aléatoire n'a pas besoin d'être sécurisé (le sel n'est pas crypté, nous ne craignons pas que quelqu'un le devine).
  • Une bonne façon d'appliquer le sel lors du hachage est d'utiliser HMAC avec votre algorithme de hachage préféré, en utilisant le mot de passe comme clé HMAC et le sel comme texte à hacher (voir cet article du document).

Exemple d'implémentation en Python, utilisant SHA-256 comme hachage sécurisé :

EDIT Comme mentionné par Eli Collins, ce n'est pas une implémentation PBKDF2. Vous devriez préférer les implémentations qui respectent la norme, telles que PassLib .

from hashlib import sha256
from hmac import HMAC
import random

def random_bytes(num_bytes):
  return "".join(chr(random.randrange(256)) for i in xrange(num_bytes))

def pbkdf_sha256(password, salt, iterations):
  result = password
  for i in xrange(iterations):
    result = HMAC(result, salt, sha256).digest() # use HMAC to apply the salt
  return result

NUM_ITERATIONS = 5000
def hash_password(plain_password):
  salt = random_bytes(8) # 64 bits

  hashed_password = pbkdf_sha256(plain_password, salt, NUM_ITERATIONS)

  # return the salt and hashed password, encoded in base64 and split with ","
  return salt.encode("base64").strip() + "," + hashed_password.encode("base64").strip()

def check_password(saved_password_entry, plain_password):
  salt, hashed_password = saved_password_entry.split(",")
  salt = salt.decode("base64")
  hashed_password = hashed_password.decode("base64")

  return hashed_password == pbkdf_sha256(plain_password, salt, NUM_ITERATIONS)

password_entry = hash_password("mysecret")
print password_entry # will print, for example: 8Y1ZO8Y1pi4=,r7Acg5iRiZ/x4QwFLhPMjASESxesoIcdJRSDkqWYfaA=
check_password(password_entry, "mysecret") # returns True

38voto

erickson Points 127945

La stratégie de base consiste à utiliser une fonction de dérivation de clé pour "hacher" le mot de passe avec un certain sel. Le sel et le résultat du hachage sont stockés dans la base de données. Lorsqu'un utilisateur saisit un mot de passe, le sel et sa saisie sont hachés de la même manière et comparés à la valeur stockée. S'ils correspondent, l'utilisateur est authentifié.

Le diable se cache dans les détails. Tout d'abord, beaucoup de choses dépendent de l'algorithme de hachage choisi. Un algorithme de dérivation de clé tel que le PBKDF2, basé sur un code d'authentification de message à base de hachage, rend "infaisable sur le plan informatique" la recherche d'une entrée (dans ce cas, un mot de passe) qui produira une sortie donnée (ce qu'un attaquant a trouvé dans la base de données).

Une attaque par dictionnaire pré-calculé utilise un index pré-calculé, ou dictionnaire, des sorties de hachage aux mots de passe. Le hachage est lent (ou est censé l'être, en tout cas), donc l'attaquant ne hachera qu'une seule fois tous les mots de passe probables, et stockera le résultat indexé de telle sorte qu'à partir d'un hachage, il puisse rechercher le mot de passe correspondant. Il s'agit d'un compromis classique entre l'espace et le temps. Comme les listes de mots de passe peuvent être énormes, il existe des moyens d'ajuster ce compromis (comme les tables arc-en-ciel), de sorte que l'attaquant puisse renoncer à un peu de vitesse pour gagner beaucoup d'espace.

Les attaques par pré-calcul sont contrecarrées par l'utilisation d'un "sel cryptographique". Il s'agit de données qui sont hachées avec le mot de passe. Ça n'a pas besoin d'être un secret, il suffit qu'il soit imprévisible pour un mot de passe donné. Pour chaque valeur de sel, un attaquant aurait besoin d'un nouveau dictionnaire. Si vous utilisez un octet de sel, un attaquant a besoin de 256 copies de son dictionnaire, chacune générée avec un sel différent. D'abord, il utilise le sel pour trouver le dictionnaire correct, puis il utilise le résultat du hachage pour trouver un mot de passe utilisable. Mais que se passe-t-il si on ajoute 4 octets ? Maintenant, il a besoin de 4 milliards de copies du dictionnaire. En utilisant un sel suffisamment grand, une attaque par dictionnaire est exclue. En pratique, 8 à 16 octets de données provenant d'un générateur de nombres aléatoires de qualité cryptographique constituent un bon sel.

Le précalcul n'étant plus possible, un attaquant doit calculer le hachage à chaque tentative. Le temps nécessaire pour trouver un mot de passe dépend maintenant entièrement du temps nécessaire pour hacher un candidat. Ce temps est augmenté par itération de la fonction de hachage. Le nombre d'itérations est généralement un paramètre de la fonction de dérivation de clé ; aujourd'hui, de nombreux appareils mobiles utilisent 10 000 à 20 000 itérations, tandis qu'un serveur peut en utiliser 100 000 ou plus. (L'algorithme bcrypt utilise le terme "facteur de coût", qui est une mesure logarithmique du temps nécessaire).

19voto

xan Points 5035

J'imagine que vous devrez ajouter une colonne à la base de données pour le mot de passe crypté, puis exécuter un travail par lot sur tous les enregistrements qui récupère le mot de passe actuel, le crypte (comme d'autres l'ont mentionné, un hachage comme md5 est assez standard). edit : mais ne doit pas être utilisé seul - voir les autres réponses pour de bonnes discussions ), l'enregistre dans la nouvelle colonne et vérifie que tout s'est bien passé.

Vous devrez alors mettre à jour votre frontal pour hacher le mot de passe saisi par l'utilisateur au moment de la connexion et le vérifier par rapport au hachage stocké, plutôt que de vérifier le texte en clair par rapport au texte en clair.

Il me semblerait prudent de laisser les deux colonnes en place pendant un certain temps pour s'assurer que rien de bizarre ne s'est produit, avant de supprimer complètement les mots de passe en clair.

N'oubliez pas non plus qu'à chaque fois que vous accédez au mot de passe, le code devra être modifié, par exemple lors des demandes de changement de mot de passe ou de rappel. Vous perdrez bien sûr la possibilité d'envoyer par e-mail les mots de passe oubliés, mais ce n'est pas une mauvaise chose. Vous devrez utiliser un système de réinitialisation de mot de passe à la place.

Modifier : Un dernier point, vous pourriez envisager d'éviter l'erreur que j'ai commise lors de ma première tentative de création d'un site web de connexion sécurisée :

Lorsque vous traitez le mot de passe de l'utilisateur, tenez compte de l'endroit où le hachage a lieu. Dans mon cas, le hachage était calculé par le code PHP fonctionnant sur le serveur web, mais le mot de passe était transmis à la page depuis la machine de l'utilisateur en clair ! Cela n'a pas posé de problème dans l'environnement dans lequel je travaillais, car il s'agissait de toute façon d'un système https (réseau universitaire). Mais, dans le monde réel, j'imagine que vous voudriez hacher le mot de passe avant qu'il ne quitte le système de l'utilisateur, en utilisant javascript etc. et ensuite transmettre le hachage à votre site.

4voto

Michael Burr Points 181287

Suivez Le conseil de Xan de garder la colonne du mot de passe actuel pendant un certain temps, de sorte que si les choses tournent mal, vous pouvez revenir en arrière rapidement et facilement.

En ce qui concerne le cryptage de vos mots de passe :

  • utiliser un sel
  • utiliser un algorithme de hachage qui est destiné aux mots de passe (c'est-à-dire, - c'est lent )

Voir l'article de Thomas Ptacek Assez avec les tables arc-en-ciel : Ce que vous devez savoir sur les systèmes de mots de passe sécurisés pour plus de détails.

3voto

Tamas Czinege Points 49277

Je pense que vous devriez faire ce qui suit :

  1. Créez une nouvelle colonne appelée HASHED_PASSWORD ou quelque chose de similaire.
  2. Modifiez votre code pour qu'il vérifie les deux colonnes.
  3. Faites migrer progressivement les mots de passe de la table non hachée vers la table hachée. Par exemple, lorsqu'un utilisateur se connecte, faites migrer automatiquement son mot de passe vers la colonne hachée et supprimez la version non hachée. Tous les utilisateurs nouvellement enregistrés auront des mots de passe hachés.
  4. Après les heures, vous pouvez exécuter un script qui migre n utilisateurs à la fois.
  5. Lorsque vous n'avez plus de mots de passe non hachés, vous pouvez supprimer votre ancienne colonne de mots de passe (il se peut que vous ne puissiez pas le faire, cela dépend de la base de données que vous utilisez). Vous pouvez également supprimer le code permettant de gérer les anciens mots de passe.
  6. C'est fait !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X