63 votes

Quel est l'algorithme de hachage par défaut utilisé par ASP.NET membership ?

Quel est l'algorithme de hachage par défaut utilisé par ASP.NET membership ? Et comment puis-je le modifier ?

50voto

Ryan Christensen Points 4064

EDIT : N'utilisez pas le fournisseur d'adhésion tel quel car il est terriblement inadéquat en termes de protection des mots de passe des utilisateurs.

Compte tenu du fait que en googlant "algorithme de hachage du fournisseur d'accès". donne cette réponse comme premier résultat, et l'évangile qui sera déduit, il m'incombe de mettre en garde les gens contre l'utilisation du fournisseur d'adhésion de cette façon et l'utilisation de hachages comme SHA-1, MD5 etc. pour obscurcir les mots de passe dans les bases de données.

tl;dr

Utilisez une fonction de dérivation de clé comme bcrypt, scrypt ou (si vous avez besoin d'une conformité FIPS) PBKDF2. avec un facteur de travail suffisant pour que le temps de hachage d'un seul mot de passe soit proche de 1000 ms ou plus.

Les hachages sont faciles à forcer de nos jours, comme en témoignent de nombreux exemples de violations de données dans l'histoire récente. Pour éviter que les mots de passe de vos utilisateurs ne se retrouvent sur pastebin lors du prochain piratage, assurez-vous que les mots de passe sont hachés avec une fonction qui prend une valeur de temps de calcul suffisamment long !

Au lieu de Membership Provider, essayez IdentityReboot ou le les nouvelles implémentations de Microsoft dont Troy Hunt parle. au moins.

Il est également intéressant de noter que sur les mêmes résultats de google mentionnés ci-dessus, je trouve une tutoriel montrant précieusement aux gens combien c'est facile pour forcer ces hachages de mots de passe en utilisant des outils populaires comme JtR ou Hashcat. Sur une plate-forme GPU personnalisée, SHA1 peut être craqué à un taux de taux stupéfiant de 48867 millions de hachages par seconde ! Avec un dictionnaire gratuit comme rockyou ou autre Une personne motivée qui s'empare de votre base de données aura très rapidement les mots de passe de la plupart de vos utilisateurs. En tant que développeur, il est de votre responsabilité éthique de faire le nécessaire pour protéger la sécurité des mots de passe de vos utilisateurs.


Le hachage par défaut est SHA1, mais il est également possible de le saler et de le baser sur 64 :

public string EncodePassword(string pass, string salt)
{
    byte[] bytes = Encoding.Unicode.GetBytes(pass);
    byte[] src = Encoding.Unicode.GetBytes(salt);
    byte[] dst = new byte[src.Length + bytes.Length];
    Buffer.BlockCopy(src, 0, dst, 0, src.Length);
    Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);
    HashAlgorithm algorithm = HashAlgorithm.Create("SHA1");
    byte[] inArray = algorithm.ComputeHash(dst);
    return Convert.ToBase64String(inArray);
}

Si vous voulez en savoir plus sur la façon de le changer, je dois encore le découvrir (à moins d'utiliser un fournisseur personnalisé, voir ci-dessous), mais SHA-1 est assez bon pour le moment. Si vous cherchez à l'inverser ou à effectuer un lookup à partir de ce code, ces personnes ont travaillé sur ce sujet : http://forums.asp.net/p/1336657/2899172.aspx

Cette question sur le SO aidera à inverser ou à reproduire cette technique si cela s'avère nécessaire. Réimplémentation de l'adhésion à ASP.NET et du hachage des mots de passe des utilisateurs en Ruby

Si vous créez un fournisseur personnalisé, vous pouvez créer vos propres algorithmes et méthodes de hachage et de cryptage.

private byte[] ConvertPasswordForStorage(string Password)
      {
         System.Text.UnicodeEncoding ue = 
      new System.Text.UnicodeEncoding();
         byte[] uePassword = ue.GetBytes(Password);
         byte[] RetVal = null;
         switch (_PasswordFormat)
         {
            case MembershipPasswordFormat.Clear:
               RetVal = uePassword;
               break;
            case MembershipPasswordFormat.Hashed:

               HMACSHA1 SHA1KeyedHasher = new HMACSHA1();
               SHA1KeyedHasher.Key = _ValidationKey;
               RetVal = SHA1KeyedHasher.ComputeHash(uePassword);
               break;
            case MembershipPasswordFormat.Encrypted:
               TripleDESCryptoServiceProvider tripleDes = new 
       TripleDESCryptoServiceProvider();
               tripleDes.Key = _DecryptionKey;
               tripleDes.IV = new byte[8];
               MemoryStream mStreamEnc = new MemoryStream();
               CryptoStream cryptoStream = new CryptoStream(mStreamEnc, 
        tripleDes.CreateEncryptor(), 
      CryptoStreamMode.Write);

               cryptoStream.Write(uePassword, 0, uePassword.Length);
               cryptoStream.FlushFinalBlock();
               RetVal = mStreamEnc.ToArray();
               cryptoStream.Close();
               break;

         }
         return RetVal;
      }

private string GetHumanReadablePassword(byte[] StoredPassword)
      {
         System.Text.UnicodeEncoding ue = new System.Text.UnicodeEncoding();
         string RetVal = null;
         switch (_PasswordFormat)
         {
            case MembershipPasswordFormat.Clear:
               RetVal = ue.GetString(StoredPassword);
               break;
            case MembershipPasswordFormat.Hashed:
               throw new ApplicationException(
        "Password cannot be recovered from a hashed format");

            case MembershipPasswordFormat.Encrypted:
               TripleDESCryptoServiceProvider tripleDes = 
        new TripleDESCryptoServiceProvider();
               tripleDes.Key = _DecryptionKey;
               tripleDes.IV = new byte[8];
               CryptoStream cryptoStream = 
        new CryptoStream(new MemoryStream(StoredPassword), 
      tripleDes.CreateDecryptor(), CryptoStreamMode.Read);
               MemoryStream msPasswordDec = new MemoryStream();
               int BytesRead = 0;
               byte[] Buffer = new byte[32];
               while ((BytesRead = cryptoStream.Read(Buffer, 0, 32)) > 0)
               {
                  msPasswordDec.Write(Buffer, 0, BytesRead);

               }
               cryptoStream.Close();

               RetVal = ue.GetString(msPasswordDec.ToArray());
               msPasswordDec.Close();
               break;
         }
         return RetVal;
      }

http://msdn.microsoft.com/en-us/library/aa479048.aspx

6 votes

La fonction EncodePassword ici ne fonctionne pas. Voir un exemple fonctionnel de "Rawbert" ci-dessous.

1 votes

Je ne suis pas d'accord avec la phrase "SHA-1 est assez bon pour le moment" dans le contexte des techniques populaires de force brute et de la vitesse à laquelle les hachages SHA-1 (et les mutations de ceux-ci) peuvent être craqués et que c'est la réponse acceptée de sorte que de nombreuses personnes vont lui accorder leur confiance.

3 votes

Il est probablement plus facile d'indiquer qu'il s'agissait de la solution en 2009, lorsque la question a été résolue, plutôt que de donner une réponse verbeuse, car j'espère que la plupart des développeurs le savent aujourd'hui. Je pense que la plupart des bons développeurs vérifient les dates des solutions et n'utilisent probablement cette solution que s'ils travaillent sur un système existant qui utilise toujours un hachage insuffisant aujourd'hui. En 2009, SHA-1 était "assez bon pour le moment", ce "moment" est passé.

40voto

Rawbert Points 156

El réponse ci-dessus par Ryan Christensen n'est pas complet. La partie où il convertit le sel en un byte[] n'est pas correcte.

Il s'agit d'un exemple concret que j'ai mis en œuvre dans une solution pour un client :

public string Hash(string value, string salt)
    {
        byte[] bytes = Encoding.Unicode.GetBytes(value);
        byte[] src = Convert.FromBase64String(salt);
        byte[] dst = new byte[src.Length + bytes.Length];
        Buffer.BlockCopy(src, 0, dst, 0, src.Length);
        Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);
        HashAlgorithm algorithm = HashAlgorithm.Create("SHA1");
        byte[] inArray = algorithm.ComputeHash(dst);
        return Convert.ToBase64String(inArray);
    }

2 votes

Heureusement, seule la lecture du sel est différente de la mise en œuvre de Ryan. Cela signifie que si vous avez un ensemble de mots de passe + sels générés par l'implémentation erronée et que vous voulez commencer à utiliser le fournisseur d'adhésion standard (ou du moins la bonne implémentation donnée ici), il vous suffit de corriger tous les sels existants dans votre base de données : var fixedSalt = Convert.ToBase64String(Encoding.Unicode.GetBytes(oldSalt);

0 votes

NON SHA1 : Nous sommes en 2020. Si vous lisez ceci, n'utilisez PAS SHA1 pour hacher les mots de passe. Utilisez au moins HashAlgorithm algorithm = HashAlgorithm.Create("SHA512"); si vous ne pouvez pas utiliser PBKDF2 ou SCRYPT ou ARGON2. PBKDF2 ou SCRYPT ou ARGON2 sont des algorithmes de hachage de mots de passe de dernière génération. Malheureusement, ils ne font pas encore partie des bibliothèques de classe natives de .NET.

28voto

MikeD Points 2229

Le type d'algorithme de hachage par défaut est SHA1. Vous pouvez le modifier de deux façons.

1) Si vous travaillez avec IIS 7, vous pouvez le mettre à jour en utilisant la configuration "Machine Key" (illustrée ci-dessous). Cela vous permet de choisir la méthode de cryptage dans une liste d'options disponibles et de spécifier les clés ou les options de génération de clés.

Machine Key configuration page from IIS 7 administration tool

2) Si vous travaillez avec IIS 6, vous pouvez changer le type d'algorithme de hachage en utilisant l'élément membership dans le fichier web.config :

<membership
    defaultProvider="provider name"
    userIsOnlineTimeWindow="number of minutes"
    hashAlgorithmType="SHA1">
    <providers>...</providers>
</membership>

Selon la documentation, la valeur de la chaîne de caractères de l'option Type d'algorithme de hachage peut être l'un des types d'algorithmes de hachage .Net fournis. En creusant un peu, on constate que les valeurs valables pour ASP.Net 2, 3 et 3.5 sont les suivantes MD5 , RIPEMD160 , SHA1 , SHA256 , SHA384 , SHA512 . La partie importante ici est que toutes ces classes héritent de HashAlgorithm .

La valeur de la Type d'algorithme de hachage peut également être une entrée de la liste cryptoNameMapping dans le fichier machine.config. Vous pouvez l'utiliser si vous avez besoin d'un algorithme de hachage tiers. Le fichier machine.config se trouve généralement à l'adresse suivante C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG si vous utilisez ASP.Net 2 ou une version ultérieure. Vous pouvez en savoir plus sur la définition de ces valeurs aquí .

5 votes

Malheureusement, Bcrypt ne figure nulle part dans ces listes.

2 votes

@Joel ASP.Net est extensible, vous pourriez donc reprendre cette implémentation ( derekslager.com/blog/posts/2007/10/ ) et l'exposer soit comme un HashAlgorithm personnalisé, soit en créant un fournisseur personnalisé comme expliqué dans l'autre réponse.

26voto

phloopy Points 4285

L'algorithme de hachage par défaut est passé à HMACSHA256 dans le cadre de .NET 4.0.

Notez que contrairement à SHA-1, HMAC SHA-256 est un hachage avec clé. Si vos hachages se comportent de manière non déterministe, vous n'avez probablement pas défini de clé, ce qui l'oblige à utiliser une clé aléatoire. Quelque chose de similaire à ce qui suit serait le coupable (c'est ce que je viens de passer une heure à comprendre :p ).

HashAlgorithm.Create(Membership.HashAlgorithmType)

Si vous souhaitez que le système fonctionne avec un fournisseur existant, vous pouvez rétablir les valeurs par défaut en utilisant la fonction ce guide .

3voto

Muhammad Akhtar Points 32101

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