2011-02-09 13 views
14

Sto trovando sorprendentemente poche informazioni sulla conversione di un database esistente da password crittografate a password Hashed. (Sono stato in grado di trovare un po 'più di informazioni sulla conversione in altro modo, ma non è stato di grande aiuto.)Modifica passwordFormat da crittografato a Hashed

Come molti sanno, la modifica dell'impostazione passwordFormat in web.config riguarda solo i nuovi utenti. Ho un database con un paio di centinaia di utenti e mi piacerebbe convertirli per utilizzare le password con hash senza modificare quelle esistenti.

Qualcun altro ha familiarità con come ci si potrebbe avvicinare a questo? Grazie per eventuali suggerimenti.

risposta

12

Questo è l'approccio mi piacerebbe iniziare con per vedere quanto ho ottenuto:

  1. Creare due MembershipProviders nel mio web.config, uno per criptato password e una per hash.
  2. Passa attraverso tutti gli utenti che utilizzano il provider di password crittografato. (SqlMembershipProvider.GetAllUsers)
  3. Ottieni la password dell'utente utilizzando il provider di password crittografato. (MembershipUser.GetPassword)
  4. Modificare la password dell'utente con la stessa password utilizzando il provider di password con hash. (MembershipUser.ChangePassword)

quindi sarebbe qualcosa di simile:

codice
<membership defaultProvider="HashedProvider"> 
     <providers> 
      <clear /> 
      <add name="HashedProvider" connectionStringName="MembershipConnectionString" enablePasswordRetrieval="false" requiresQuestionAndAnswer="false" applicationName="MyApp" passwordFormat="Hashed" type="System.Web.Security.SqlMembershipProvider" /> 
      <add name="EncryptedProvider" connectionStringName="MembershipConnectionString" enablePasswordRetrieval="true" requiresQuestionAndAnswer="false" applicationName="MyApp" passwordFormat="Encrypted" type="System.Web.Security.SqlMembershipProvider" /> 
     </providers> 
    </membership> 

:

SqlMembershipProvider hashedProvider = (SqlMembershipProvider)Membership.Providers["HashedProvider"]; 
SqlMembershipProvider encryptedProvider = (SqlMembershipProvider)Membership.Providers["EncryptedProvider"]; 

int unimportant; 
foreach (MembershipUser user in encryptedProvider.GetAllUsers(0, Int32.MaxValue, out unimportant)) 
{ 
    hashedProvider.ChangePassword(user.UserName, user.GetPassword(), user.GetPassword()); 
} 
+1

Attualmente sto cercando di aggiornare le password di testo in chiaro alle password crittografate. Li voglio hash ma il client no. Ad ogni modo, questa soluzione sembra promettente. Molto elegante nella sua semplicità. Spero funzioni. – mikesigs

+2

Ho funzionato, ma i caveat erano troppo da sopportare. Prima di tutto, non puoi semplicemente chiamare ChangePassword sul provider con hash perché devi fornire la password esistente (che tenta di hash per confrontare il valore db che non è hash). Quindi devi chiamare ResetPassword per ottenere una password hash temporanea per chiamare ChangePassword. La performance è l'assassino. È necessario recuperare ciascun utente di appartenenza, quindi chiamare GetPassword, ResetPassword e ChangePassword per ciascuno. Oltre 3 * N colpi sul db! L'ho concluso in una transazione e ho esaurito rapidamente il mio conn pool. – mikesigs

+0

Esaminerò una procedura memorizzata CLR in modo da poter chiamare i meccanismi di crittografia del provider da SQL. Pubblicherò di nuovo se funziona. – mikesigs

1

Ti metterei in guardia contro l'hashing delle tue password in modo casuale poiché ci sono molte avvertenze su questo approccio. Questo Blog post about hashing passwords è stato molto perspicace per me, e penso che dovresti leggerlo. Perché vuoi le password con hash anziché crittografate?

+3

Grazie per il collegamento, è stata una lettura interessante. Detto questo, nessun metodo è sicuro al 100% e le password di hashing sono gli attuali standard del settore per l'archiviazione delle password. Avevo impostato il mio sito per utilizzare le password crittografate come comodità per gli utenti (posso inviarlo via email a loro), ma mi sono lamentato che questo rappresentava un rischio per i miei utenti, soprattutto quando usano la stessa password su più siti. –

2

Per motivi di sicurezza, è sicuramente la decisione giusta per passare dalle password crittografate agli hash nel database.

Generalmente per creare hash fuori le password criptate esistenti, si deve prima di loro decifrare e poi li hash. Essere consapevoli del fatto che perderai (quando finalmente cambierai) le password originali. Invece avrai un'impronta digitale (hash) unica delle password degli utenti.

Pensate anche di usare il sale per l'hashing (difesa contro rainbow tables ecc) e hanno anche uno sguardo in algoritmi di hashing lento come BCrypt (Codeplex & Article: How To Safely Store A Password) per motivi di sicurezza, invece di quelli veloci come MD5.

Tenete anche a mente che sarà molto più difficile cambiare l'algoritmo di hashing in futuro che cambiarlo dall'ecryption all'hash. Così si vuole fare bene la prima volta;)

+0

Sì, ho capito quali sono le password hash e come non è possibile convertire da hash alla password originale. E so che ho bisogno di decifrare le password criptate e poi cancellarle. Quello che non so è come posso farlo per tutti i record in un modo che funzionerà quindi con l'appartenenza ad ASP.NET. (A proposito, l'appartenenza ASP.NET non usa le password hash?) –

+1

L'algoritmo hash predefinito dell'appartenenza ASP.NET è SHA1 e usano salt cododed come Base64. –

12

soluzione di Greg è un buon inizio, ma non interesserà gli utenti esistenti. SqlMembershipProvider protegge gli utenti e le password esistenti memorizzando il PasswordFormat (0 = clear, 1 = Hashed, 2 = Encrypted) nella tabella insieme alle password. La modifica del formato della password del provider influisce solo sugli inserimenti nelle tabelle degli utenti.Per convertire le password degli utenti esistenti in Hashed, è necessario modificare il parametro PasswordFormat per ogni voce. Ecco un modo semplice per farlo:

void HashAllPasswords() 
{ 
    var clearProvider = Membership.Providers["SqlProvider_Clear"]; 
    var hashedProvider = Membership.Providers["SqlProvider_Hashed"]; 
    int dontCare; 
    if (clearProvider == null || hashedProvider == null) return; 
    var passwords = clearProvider.GetAllUsers(0, int.MaxValue, out dontCare) 
     .Cast<MembershipUser>().ToDictionary(u => u.UserName, u => u.GetPassword()); 

    using (var conn = new SqlConnection(
      ConfigurationManager.ConnectionStrings[0].ConnectionString)) 
    { 
     conn.Open(); 
     using (var cmd = new SqlCommand(
       "UPDATE [aspnet_Membership] SET [PasswordFormat]=1", conn)) 
      cmd.ExecuteNonQuery(); 
    } 

    foreach (var entry in passwords) 
    { 
     var resetPassword = hashedProvider.ResetPassword(entry.Key, null); 
     hashedProvider.ChangePassword(entry.Key, resetPassword, entry.Value); 
    } 
} 
+0

Grazie per la risposta tardiva. In realtà, questo compito è ancora sul mio backburner e non avevo davvero una tecnica specifica. Esplorerò questo codice più a fondo quando avrò un po 'di tempo. –

+0

+1 funziona perfettamente – ajbeaven

+0

Quando si ricevono tutte le password degli utenti, è necessario filtrare gli utenti bloccati. Altrimenti fallirà al reset/cambiamento della password. –

Problemi correlati