Asp.net

重新使用現有 Microsoft 標識使用者表時密碼(雜湊)不匹配

  • February 6, 2020

我們有一個帶有Microsoft 標識表的現有 SQL 數據庫,最初由 ASP.NET Core 應用程序生成。

我們還有一個 ASP.NET 4 應用程序,它也使用 Microsoft Identity。

我們希望 ASP.NET 4 應用能夠使用與原始 .NET Core 應用相同的數據庫來驗證登錄。

但是,當我們嘗試驗證密碼時,它們不匹配。

我只是猜測 .NET Core 應用程序生成的密碼雜湊無法通過 ASP.NET 4 應用程序進行驗證,但我不確定從這裡去哪裡。:)

.NET Core 應用程序中沒有自定義密碼散列,我正在努力尋找任何可能影響散列的配置?

非常感謝任何幫助或指針!

**編輯:**這似乎是由 Identity V2/V3 中的不同雜湊算法引起的。不過,不確定如何在 ASP.NET 4 應用程序中模擬 V3 雜湊算法。

根據位於的文件:https ://github.com/aspnet/Identity/blob/a8ba99bc5b11c5c48fc31b9b0532c0d6791efdc8/src/Microsoft.AspNetCore.Identity/PasswordHasher.cs

   /* =======================
    * HASHED PASSWORD FORMATS
    * =======================
    * 
    * Version 2:
    * PBKDF2 with HMAC-SHA1, 128-bit salt, 256-bit subkey, 1000 iterations.
    * (See also: SDL crypto guidelines v5.1, Part III)
    * Format: { 0x00, salt, subkey }
    *
    * Version 3:
    * PBKDF2 with HMAC-SHA256, 128-bit salt, 256-bit subkey, 10000 iterations.
    * Format: { 0x01, prf (UInt32), iter count (UInt32), salt length (UInt32), salt, subkey }
    * (All UInt32s are stored big-endian.)
    */

有一次,identity 使用了不同的散列算法——也許它在一個中使用版本 2 格式,而在另一個中使用版本 3 格式?

類的建構子接受選項,您可以嘗試調整它以獲得正確的雜湊?

public PasswordHasher(IOptions<PasswordHasherOptions> optionsAccessor = null)

編輯:

我在這裡找到了 Identity v2.0 源:https ://aspnetidentity.codeplex.com/和 git repo:https ://git01.codeplex.com/aspnetidentity

查看原始碼,您會遇到它的散列方法。

Crypto.HashPassword.cs

public static string HashPassword(string password)
   {
       if (password == null)
       {
           throw new ArgumentNullException("password");
       }

       // Produce a version 0 (see comment above) text hash.
       byte[] salt;
       byte[] subkey;
       using (var deriveBytes = new Rfc2898DeriveBytes(password, SaltSize, PBKDF2IterCount))
       {
           salt = deriveBytes.Salt;
           subkey = deriveBytes.GetBytes(PBKDF2SubkeyLength);
       }

       var outputBytes = new byte[1 + SaltSize + PBKDF2SubkeyLength];
       Buffer.BlockCopy(salt, 0, outputBytes, 1, SaltSize);
       Buffer.BlockCopy(subkey, 0, outputBytes, 1 + SaltSize, PBKDF2SubkeyLength);
       return Convert.ToBase64String(outputBytes);
   }

與 aspnet 身份核心中的 v2 相比:

   private static byte[] HashPasswordV2(string password, RandomNumberGenerator rng)
   {
       const KeyDerivationPrf Pbkdf2Prf = KeyDerivationPrf.HMACSHA1; // default for Rfc2898DeriveBytes
       const int Pbkdf2IterCount = 1000; // default for Rfc2898DeriveBytes
       const int Pbkdf2SubkeyLength = 256 / 8; // 256 bits
       const int SaltSize = 128 / 8; // 128 bits

       // Produce a version 2 (see comment above) text hash.
       byte[] salt = new byte[SaltSize];
       rng.GetBytes(salt);
       byte[] subkey = KeyDerivation.Pbkdf2(password, salt, Pbkdf2Prf, Pbkdf2IterCount, Pbkdf2SubkeyLength);

       var outputBytes = new byte[1 + SaltSize + Pbkdf2SubkeyLength];
       outputBytes[0] = 0x00; // format marker
       Buffer.BlockCopy(salt, 0, outputBytes, 1, SaltSize);
       Buffer.BlockCopy(subkey, 0, outputBytes, 1 + SaltSize, Pbkdf2SubkeyLength);
       return outputBytes;
   }

身份 v2 散列和身份核心 v2 散列看起來非常相似,現在與身份核心 v3 散列相比:

   private static byte[] HashPasswordV3(string password, RandomNumberGenerator rng, KeyDerivationPrf prf, int iterCount, int saltSize, int numBytesRequested)
   {
       // Produce a version 3 (see comment above) text hash.
       byte[] salt = new byte[saltSize];
       rng.GetBytes(salt);
       byte[] subkey = KeyDerivation.Pbkdf2(password, salt, prf, iterCount, numBytesRequested);

       var outputBytes = new byte[13 + salt.Length + subkey.Length];
       outputBytes[0] = 0x01; // format marker
       WriteNetworkByteOrder(outputBytes, 1, (uint)prf);
       WriteNetworkByteOrder(outputBytes, 5, (uint)iterCount);
       WriteNetworkByteOrder(outputBytes, 9, (uint)saltSize);
       Buffer.BlockCopy(salt, 0, outputBytes, 13, salt.Length);
       Buffer.BlockCopy(subkey, 0, outputBytes, 13 + saltSize, subkey.Length);
       return outputBytes;
   }

我不會假裝理解這些方法中發生了什麼,但是從標識 v2 和標識核心,我們從無參數建構子變為接受配置選項的建構子。V2 使用 SHA1,V3 使用 SHA256(除其他外)。

看起來預設情況下,身份核心將使用 V3 方法進行雜湊處理,這在舊版本的身份中不存在 - 這將是您的問題的原因。

https://github.com/aspnet/Identity/blob/a8ba99bc5b11c5c48fc31b9b0532c0d6791efdc8/src/Microsoft.AspNetCore.Identity/PasswordHasherOptions.cs

注意在上面的源碼中,V3 被用作預設值。

   /// <summary>
   /// Gets or sets the compatibility mode used when hashing passwords.
   /// </summary>
   /// <value>
   /// The compatibility mode used when hashing passwords.
   /// </value>
   /// <remarks>
   /// The default compatibility mode is 'ASP.NET Identity version 3'.
   /// </remarks>
   public PasswordHasherCompatibilityMode CompatibilityMode { get; set; } = PasswordHasherCompatibilityMode.IdentityV3;

不幸的是,這看起來意味著您在身份核心中散列的密碼不能在舊版本的身份中進行相同的散列,因為舊的方法沒有實現。也許您可以創建自己的模仿 v3 中所做的事情?

引用自:https://stackoverflow.com/questions/38227829