2011-02-09 20 views
14

Estoy encontrando muy poca información sobre la conversión de una base de datos existente de contraseñas encriptadas a contraseñas hash. (Pude encontrar un poco más de información sobre la conversión en otra dirección, pero no fue de mucha ayuda.)Cambiar el formato de contraseña de cifrado a hash

Como la mayoría de la gente sabe, cambiar la configuración passwordFormat en web.config solo afecta a los usuarios nuevos. Tengo una base de datos con un par de cientos de usuarios y me gustaría convertirlos para usar contraseñas hash sin cambiar esas contraseñas existentes.

¿Alguien más está familiarizado con cómo se podría abordar esto? Gracias por cualquier consejo.

Respuesta

12

Este es el enfoque que empezaría con ver lo lejos que tengo:

  1. Cree dos MembershipProviders en mi web.config, uno para cifrada contraseñas y una para hash.
  2. Pasa por todos los usuarios utilizando el proveedor de contraseñas encriptadas. (SqlMembershipProvider.GetAllUsers)
  3. Obtenga la contraseña del usuario utilizando el proveedor de contraseñas cifradas. (MembershipUser.GetPassword)
  4. Cambie la contraseña del usuario a la misma contraseña utilizando el proveedor de contraseñas hash. (MembershipUser.ChangePassword)

así que sería algo como esto:

<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> 

código:

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

Actualmente estoy tratando de actualizar las contraseñas de texto sin cifrar a las contraseñas encriptadas. Los quiero hash, pero el cliente no. De todos modos, esta solución parece prometedora. Muy elegante en su simplicidad. Espero que funcione. – mikesigs

+2

Lo hice funcionar pero las advertencias eran demasiado difíciles de soportar. En primer lugar, no puede simplemente llamar a ChangePassword en el proveedor de hash porque debe proporcionar la contraseña existente (que intenta hacer hash para compararla con el valor de db que no es hash). Por lo tanto, debe llamar a ResetPassword para obtener una contraseña hash temporal para llamar a ChangePassword. El rendimiento es el asesino. Debe recuperar cada MembershipUser, luego llamar GetPassword, ResetPassword y ChangePassword para cada uno. ¡Más de 3 * N hits en el db! Lo envolví en una transacción y agotó rápidamente mi grupo de conexión. – mikesigs

+0

Voy a investigar un procedimiento almacenado CLR para poder llamar a los mecanismos de cifrado del proveedor desde SQL. Voy a publicar de nuevo si eso funciona. – mikesigs

1

Te advierto que no hagas tus contraseñas al azar ya que hay muchas advertencias sobre ese enfoque. Este Blog post about hashing passwords fue muy perspicaz para mí, y creo que deberías leerlo. ¿Por qué quieres contraseñas hash en lugar de cifradas?

+3

Gracias por el enlace, fue una lectura interesante. Dicho esto, ningún método es 100% seguro, y las contraseñas hash es el estándar actual de la industria para el almacenamiento de contraseñas. Había configurado mi sitio para que utilizara contraseñas encriptadas para comodidad de los usuarios (puedo enviárselas por correo electrónico), pero recibí quejas de que esto representaba un riesgo para mis usuarios, especialmente cuando usan la misma contraseña en varios sitios. –

2

Por razones de seguridad, definitivamente es la decisión correcta cambiar de contraseñas encriptadas a hashes en su base de datos.

general para crear hashes fuera de sus contraseñas cifradas existentes, primero debe descifrarlos y luego hash de ellos. Tenga en cuenta que perderá (cuando finalmente cambie) las contraseñas originales. En su lugar, tendrá una huella digital única (hash) de las contraseñas de los usuarios.

Piense también en el uso de sal para el hash (defensa contra rainbow tables etc.) y también tienen una mirada en algoritmos hash lentos como BCrypt (Codeplex & Article: How To Safely Store A Password) por razones de seguridad en lugar de los rápidos como MD5.

Tenga en cuenta también que será mucho más esfuerzo cambiar el algoritmo de hash en el futuro que cambiarlo de ecryption a hash. Así que usted quiere hacer las cosas bien la primera vez;)

+0

Sí, entiendo qué son las contraseñas hash y cómo no puede convertir el hash a la contraseña original. Y sé que necesito descifrar las contraseñas encriptadas y luego las hash. Lo que no sé es cómo puedo hacer esto para todos los registros de una manera que luego funcione con la membresía de ASP.NET. (Por cierto, ¿la membresía de ASP.NET no usa una sal para contraseñas hash?) –

+1

El algoritmo hash predeterminado de membresía de ASP.NET es SHA1 y usan sal codificado como Base64. –

12

solución de Greg es un buen comienzo, pero no afectará a los usuarios existentes. El SqlMembershipProvider protege a los usuarios y contraseñas existentes almacenando PasswordFormat (0 = clear, 1 = Hashed, 2 = Encrypted) en la tabla junto con las contraseñas. Cambiar el formato de contraseña del proveedor solo afecta las inserciones en las tablas de usuario.Para convertir las contraseñas de los usuarios existentes a Hashed, debe cambiar el parámetro PasswordFormat para cada entrada. Aquí hay una manera simple de hacerlo:

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

Gracias por su respuesta tardía. De hecho, esta tarea todavía está en mi backburner y realmente no tenía una técnica específica. Exploraré este código más profundamente cuando tenga algo de tiempo. –

+0

+1 funciona perfectamente – ajbeaven

+0

Al obtener las contraseñas de todos los usuarios, debe filtrar a los usuarios bloqueados. De lo contrario, fallará en el restablecimiento de contraseña/cambio de etapa. –

Cuestiones relacionadas