signout net mvc formsauthentication asp .net forms-authentication

.net - net - Suelta el reemplazo de FormsAuthentication.HashPasswordForStoringInConfigFile?



formsauthentication mvc 5 (4)

Después de actualizar a .Net 4.5, ahora recibo la advertencia de que "System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile está obsoleto" y la sugerencia es utilizar las API de membresía.

Esto está muy bien y es bueno para nuevos proyectos, pero en esta etapa (con datos de usuario y contraseñas hash existentes), no puedo cambiar a un proveedor de membresía personalizado con formas potencialmente diferentes de hash.

¿Cuál es el camino recomendado para problemas como este? Continuar utilizando llamadas "obsoletas" obviamente no es la ruta sugerida, por lo que ha sido reemplazado por otra cosa que no sea "solo use las API de membresía".


¿Cuál es el camino recomendado para problemas como este? Continuar utilizando llamadas "obsoletas" obviamente no es la ruta sugerida, por lo que ha sido reemplazado por otra cosa que no sea "solo use las API de membresía".

La mejor forma (que hayas descartado) puramente dentro de .NET Framework es cambiar todo para que las contraseñas sean procesadas por PBKDF2, Bcrypt o Scrypt. PBKDF2 se proporciona en .NET por la clase Rfc2898DeriveBytes .

La segunda mejor manera es terminar con dos "versiones" de contraseñas:

  • La versión 0 habría sido la antigua HashPasswordForStoringInConfigFile, pero puedes actualizarla a granel, sin conexión, a la Versión 1 y eliminar esos viejos hashes antes de que nadie los robe y terminas en las noticias de comercio con el hashing de contraseña vintage patético de los 90.
  • La versión 1, que es la PBKDF2 del valor existente HashPasswordForStoringInConfigFile! Es decir, toma los hash viejos y desagradables, y PBKDF2 con un nuevo sal aleatorio y un alto número de iteraciones, y almacena el resultado. Luego, cuando un usuario quiere iniciar sesión, ingresa su contraseña en el código @ RichardBažant escribió, por lo que tiene lo que HashPasswordForStoringInConfigFile habría devuelto, y luego aplica PBKDF2 a ese resultado.
    • es decir, en realidad es Rfc2898DeriveBytes (HashPasswordForStoringInConfigFile (contraseña)), PerUserSalt, YourIterations.
  • Versión 2, a la que los usuarios que tienen hashes de la Versión 1 se actualizan. Todas las columnas excepto "versión" son iguales, pero después de calcular y validar la Versión 1, se calcula Rfc2898DeriveBytes (contraseña), PerUserSalt, YourIterations) y se reemplaza el hash de la versión 1 con el hash de la versión 2 (y se cambia la versión a 2, por supuesto).

La tercera mejor manera es la segunda mejor manera, pero con solo la versión 1. Tenga cuidado, de esta manera se encuentra la locura DCC2 : usted continúa envolviendo su salida anterior dentro de los algoritmos más nuevos.

En ambos casos, almacenará los resultados PBKDF2-HMAC-SHA-1 en la base de datos, por lo que necesitará:

  • Hash de contraseña (BINARY (20)) - es decir, la salida PBKDF2.
  • Su sal (BINARY (16), generado por usuario por RNGCryptoServiceProvider Class )
  • Opcional: Número de iteraciones de PBKDF2 (INT, comienza en decenas de miles y aumenta justo antes de que su servidor esté vinculado a la CPU a la carga máxima; aumente a medida que su hardware se actualice)
    • Esto le permite aumentar de forma transparente su nivel de seguridad cada vez que un usuario ingresa su contraseña (correcta). Primero validando que sea correcta y luego vuelva a procesarla con un recuento de iteraciones más alto.
  • Opcional: una "versión" (TINYINT), por lo que la actualización a otro algoritmo más tarde es más fácil, ya que puede tener más de una versión activa a la vez.

PS para el algoritmo más nuevo de la Versión 1 o Versión 2, Jither creó una biblioteca .NET capaz de PBKDF2-HMAC-SHA256, PBKDF2-HMAC-SHA512, y así sucesivamente; mi repositorio Github contiene una variante de este con un conjunto razonable de vectores de prueba.


¿Por qué no puede usar el más simple de .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); }


Esta es una solución para 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; }

Para MD5 solo necesita cambiar el algoritmo a:

MD5 algorithm = MD5.Create();

Espero que no te importe, solo voy a agregar una variante VB.NET de tu código anterior:

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


La respuesta de Richard funcionó para mí genial. Este es el código descompilado de .NET Framework 4.5. Si alguien está mejor, úsala. Supongo que puede ser un poco más rápido.

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