2012-11-23 3 views
34

Dopo l'aggiornamento a .Net 4.5, ora sto ricevendo l'avvertimento che "System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile è obsoleto" e il suggerimento è quello di utilizzare le API di appartenenza, invece.Interruzione della sostituzione di FormsAuthentication.HashPasswordForStoringInConfigFile?

Questo è tutto molto bene e buono per i nuovi progetti, ma in questa fase (con i dati dell'utente e hash password esistenti), non posso cambiare molto bene ad un provider di appartenenze personalizzato con potenziali diversi modi di hashing.

cosa è il raccomandato via da seguire per problemi come questo? Continuare a utilizzare chiamate "obsolete" non è ovviamente il percorso suggerito, quindi è stato sostituito da qualcos'altro oltre a "basta usare le API di appartenenza"?

+0

HashPasswordForStoringInConfigFile è vecchio, e per qualcuno a suggerire un'alternativa sostitutiva allora devono conoscere il secondo parametro è lo "MD5" o "SHA1"? Sì, SO CHE questo post è VECCHIO ma ci siamo imbattuti in esso perché non avevo usato 'HashPasswordForStoringInConfigFile' in molti anni. Le sostituzioni SHA1 per la password di sale + sono valide, ma a questo punto nel 2016 è semplicemente una cattiva idea quella di rimanere con SHA1 e tanto meno l'orribile MD5 –

risposta

43

Questa è una soluzione per la variante SHA1.

 public static string GetSwcSHA1(string value) 
    { 
     SHA1 algorithm = SHA1.Create(); 
     byte[] data = algorithm.ComputeHash(Encoding.UTF8.GetBytes(value)); 
     string sh1 = ""; 
     for (int i = 0; i < data.Length; i++) 
     { 
      sh1 += data[i].ToString("x2").ToUpperInvariant(); 
     } 
     return sh1; 
    } 

Per MD5 si solo bisogno di modificare l'algoritmo a:

MD5 algorithm = MD5.Create(); 

Spero che non ti dispiaccia, solo andando ad aggiungere una variante VB.NET del codice di cui sopra:

Public Shared Function CreateHash(saltAndPassword) As String 
     Dim Algorithm As SHA1 = SHA1.Create() 
     Dim Data As Byte() = Algorithm.ComputeHash(Encoding.UTF8.GetBytes(saltAndPassword)) 
     Dim Hashed As String = "" 

     For i As Integer = 0 To Data.Length - 1 
      Hashed &= Data(i).ToString("x2").ToUpperInvariant() 
     Next 

     Return Hashed 
    End Function 
+0

Molto utile, grazie! Andrebbe bene se avessi aggiornato VB.Net per includere la dichiarazione delle funzioni e così via? –

+0

cosa significa Swc in GetSwcSH1? – Wes

2

la risposta di Richard ha lavorato per me grande. Questo è il codice compilato da .NET Framework 4.5. Se qualcuno è meglio, per favore usalo. Immagino che potrebbe essere un po 'più veloce.

 public static string BinaryToHex(byte[] data) 
     { 
      if (data == null) 
      { 
       return null; 
      } 
      char[] hex = new char[checked((int)data.Length * 2)]; 
      for (int i = 0; i < (int)data.Length; i++) 
      { 
       byte num = data[i]; 
       hex[2 * i] = NibbleToHex((byte)(num >> 4)); 
       hex[2 * i + 1] = NibbleToHex((byte)(num & 15)); 
      } 
      return new string(hex); 
     } 

     private static char NibbleToHex(byte nibble) 
     { 
      int aChar = (nibble < 10 ? nibble + 48 : nibble - 10 + 65); 
      return (char)aChar; 
     } 
9

cosa è il raccomandato via da seguire per problemi come questo? Continuare a utilizzare chiamate "obsolete" non è ovviamente il percorso suggerito, quindi è stato sostituito da qualcos'altro oltre a "basta usare le API di appartenenza"?

Il modo migliore (che hai escluso) esclusivamente all'interno di .NET Framework è quello di cambiare tutto per fare in modo che le password vengano cancellate da PBKDF2, Bcrypt o Scrypt. PBKDF2 è fornito in .NET dal Rfc2898DeriveBytes Class.

Il secondo modo migliore è quello di finire con due "versioni" di password:

  • Versione 0 sarebbe stato il vecchio HashPasswordForStoringInConfigFile, ma è possibile aggiornare quelli in massa, non in linea, per la versione 1 e rimuovere quei vecchi hash interi prima che qualcuno li rubi e finisci nelle notizie commerciali come avere hashing di password vintage patetico degli anni '90.
  • versione 1, che è il PBKDF2 del valore HashPasswordForStoringInConfigFile esistente! Cioè prendi i tuoi vecchi e brutti hash attuali e li PBKDF2 con un nuovo salt random e un numero elevato di iterazioni e memorizza il risultato. Poi, quando un utente vuole effettuare il login, è nutrire la loro password per il codice @ RichardBažant ha scritto, in modo da avere quello HashPasswordForStoringInConfigFile sarebbe tornato, e poi si applicano PBKDF2 a questo risultato!
    • vale a dire in realtà è Rfc2898DeriveBytes (HashPasswordForStoringInConfigFile (password)), PerUserSalt, YourIterations)
  • versione 2, che gli utenti che hanno la versione 1 hash vengono aggiornati a.Tutte le colonne tranne "versione" sono le stesse, ma dopo aver calcolato e convalidato la Versione 1, si calcolano Rfc2898DeriveBytes (password), PerUserSalt, YourIterations) e si sostituisce l'hash della versione 1 con l'hash della versione 2 (e si modifica la versione in 2, ovviamente).

Il terzo modo migliore è il modo migliore secondo, ma solo con la versione 1. Attenzione, in questo modo si trova DCC2 follia - si mantiene avvolgendo il vecchio uscita all'interno degli algoritmi più recenti

In entrambi i casi, è' ll essere Memorizzazione PBKDF2-HMAC-SHA-1 risultati nel database, quindi avrai bisogno di:

  • password hash (BINARIO (20)) - cioè l'uscita PBKDF2.
  • vostro sale (BINARIO (16), generato per utente da RNGCryptoServiceProvider Class)
  • opzionale: numero di iterazioni PBKDF2 (INT, iniziare a decine di migliaia e andare fino a poco prima che il vostro server sarà CPU bound al massimo caricare come aumentare l'hardware)
    • Ciò consente di aumentare in modo trasparente il livello di sicurezza ogni volta che un utente immette la propria password (corretta). Prima convalidare è corretto, quindi reimmarlo con un numero di iterazioni più elevato
  • Opzionale: una "versione" (TINYINT) in modo che l'aggiornamento a un altro algoritmo in un secondo momento sia più semplice, peccato ce puoi avere più di una versione attiva in una sola volta.

P.S. per l'algoritmo più recente versione 1 o versione 2, Jither ha creato una libreria .NET in grado di PBKDF2-HMAC-SHA256, PBKDF2-HMAC-SHA512 e così via; my Github repository contiene una variante di esso con un ragionevole insieme di vettori di test.

2

Perché non è possibile utilizzare la più semplice da Net

public static string HashString(string inputString, string hashName) 
{ 
    var algorithm = HashAlgorithm.Create(hashName); 
    if (algorithm == null) 
    throw new ArgumentException("Unrecognized hash name", hashName); 

    byte[] hash = algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString)); 
    return Convert.ToBase64String(hash); 
} 
+0

Sì, theHashAlgorithm è molto flessibile Sono d'accordo con te. Quindi se è SHA1, in sostanza sarebbe passato nel metodo di creazione come HashAlgorithm.Create ("SHA-1") –