首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当重新使用现有Microsoft标识用户表时,密码(散列)不匹配。

当重新使用现有Microsoft标识用户表时,密码(散列)不匹配。
EN

Stack Overflow用户
提问于 2016-07-06 15:28:13
回答 2查看 4.5K关注 0票数 8

我们有一个现有的带有微软标识表的SQL数据库,最初是由ASP.NET核心应用程序生成的。

我们也有一个ASP.NET 4应用程序,它也使用微软的身份。

我们希望ASP.NET 4应用程序能够使用与原始.NET核心应用相同的数据库来验证登录。

然而,当我们试图验证密码时,它们并不匹配。

我只是猜测.NET核心应用程序生成的密码哈希不能被ASP.NET 4应用程序验证,但我不知道从哪里开始。:)

在.NET核心应用程序中没有自定义密码散列,而且我很难找到任何可能影响哈希的配置?

任何帮助或指针都是非常感谢的!

编辑:,这似乎是由标识V2/V3中的不同哈希算法造成的。不过,不知道如何在V3 4应用程序中模仿ASP.NET哈希算法。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-07-06 15:50:01

根据所找到的文档:https://github.com/aspnet/Identity/blob/a8ba99bc5b11c5c48fc31b9b0532c0d6791efdc8/src/Microsoft.AspNetCore.Identity/PasswordHasher.cs

代码语言:javascript
复制
    /* =======================
     * 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.)
     */

在某种程度上,身份使用了不同的哈希算法--也许它在一个版本中使用了版本2格式,而在另一个版本中使用了版本3格式?

类的构造函数接受选项,您可以尝试调整它以获得正确的散列吗?

代码语言:javascript
复制
public PasswordHasher(IOptions<PasswordHasherOptions> optionsAccessor = null)

编辑:

我在这里找到了Identity v2.0源代码:https://aspnetidentity.codeplex.com/和git:https://git01.codeplex.com/aspnetidentity

通过源代码,您可以看到它的散列方法。

Crypto.HashPassword.cs

代码语言:javascript
复制
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);
    }

与v2相比,在aspnet标识核中:

代码语言:javascript
复制
    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哈希相比:

代码语言:javascript
复制
    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;
    }

我不打算假装理解这些方法中发生了什么,但是从identity v2和identity核心,我们从一个无参数构造函数过渡到一个接受配置选项的构造函数。V2使用SHA1,V3使用SHA256 (等等)。

看起来,在默认情况下,身份核心会使用V3方法进行散列,在旧版本的identity中不存在这种方法--这将是导致您的问题的原因。

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

注在上面的源代码中,V3被用作缺省值。

代码语言:javascript
复制
    /// <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中所做的事情?

票数 6
EN

Stack Overflow用户

发布于 2020-01-23 12:58:22

接下来,Kritner给出了一个TLDR的最佳答案:

如果要从Microsoft.AspNet.Identity.Core迁移到Microsoft.AspNetCore.Identity (请注意要替换的细微差别)

代码语言:javascript
复制
// Microsoft.AspNet.Identity.Core
PasswordHasher hasher = new PasswordHasher(); 

看上去就像

代码语言:javascript
复制
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;

// Microsoft.AspNetCore.Identity
PasswordHasher<YourUserTypeActuallyImmaterial> hasher 
= new PasswordHasher<YourUserTypeActuallyImmaterial>(
                Options.Create(new PasswordHasherOptions()
                {
                    CompatibilityMode = PasswordHasherCompatibilityMode.IdentityV2,
                }));

此后,API的不同之处在于,较新的PasswordHasher<T>要求您在散列或验证时传递T实例。

,这将以与旧方法兼容的方式散列明文,并将成功验证使用前一种方法散列的有效密码。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38227829

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档