ASP.NET 成员资格 HashAlgorithmType 默认为 HMACSHA256,那么密码哈希是键控的吗?

ASP.NET membership HashAlgorithmType defaults to HMACSHA256, so is password hash keyed?

我有一个使用 SqlMembershipProvider 的 ASP.NET 4.5 网络应用程序。在开发过程中,有人将 passwordFormat="Clear" 放入配置中,导致密码以明文形式保存。我想删除它并启用密码散列,但我想确保散列不是使用特定于机器或自动生成的密钥生成的。

根据我在所有相关问答中阅读的内容,密码只是使用直接 SHA256 进行哈希处理,而不是特定于机器或密钥的。但是,当我在 运行 时检查 Membership.HashAlgorithmType 时,它的值为 "HMACSHA256" 并且 .NET HMACSHA256 class 需要一个密钥(因为它是 HMAC)并且随机生成一个如果一个不提供给构造函数。所以看来一定有一把钥匙参与其中。那么会员密码哈希值是否加密?如果是,我如何跨机器使用相同的密钥?支持您的答案的文档或证据将不胜感激。

编辑

根据 this MSDN page on "Securing Membership",machineKey 元素 确实 控制哈希键:

It is highly recommended that you encrypt user passwords in the membership data source using a passwordFormat attribute set to Hashed or Encrypted, where Hashed is the most secure format. The encryption key values for the specified encryption algorithm are stored in the machineKey configuration element.

但是,我尝试在 web.config 中设置机器密钥验证密钥,它仍然生成与设置之前相同的密码哈希,所以它似乎没有效果。

我也一直在查看 SqlMembershipProvider source code,据我所知,它确实使用了键控哈希。当然,这是 .Net 4.6.1 的来源,而我是 运行ning 4.5。我已经复制了 EncodePassword 源代码并对其进行了修改,因此它可以 运行 在控制台应用程序和我的控制台应用程序中,我仍然得到与 MembershipProvider 结果(在同一台机器上)不同的哈希值相同的密码和盐值。

如果它使用随机密钥,您将无法验证密码。那么 SqlMembershipProvider 从哪里得到它的哈希键?

在源代码和网上进行更多挖掘之后,我在 SO 上发现了一个问题,用户注意到 his/her SQLMembershipProvider 哈希在数据库中只有 20 个字节。他们应该是 64 岁。我检查了我的,他们也是。我试图确定 SHA256 哈希如何最终只有 20 个字节,并得出它不能的结论。所以在我的控制台应用程序中,我尝试只使用 SHA1 来解决这个问题。我将其结果与 SQLMembershipProvider 创建的散列进行了比较,果然,它匹配了!我的 SQLMembershipProvider 正在使用 SHA1,尽管 Membership.HashAlgorithmType 表明它设置为 .NET 4.0 默认值,"HMACSHA256".

这就是我阅读源代码的用武之地。我记得我从我的控制台应用程序中删除了一个条件部分,该部分在创建哈希算法时检查某些旧模式 class.

        private HashAlgorithm GetHashAlgorithm() {
        if (s_HashAlgorithm != null)
            return HashAlgorithm.Create(s_HashAlgorithm);

        string temp = Membership.HashAlgorithmType;
        if (_LegacyPasswordCompatibilityMode == MembershipPasswordCompatibilityMode.Framework20 &&
            !Membership.IsHashAlgorithmFromMembershipConfig &&
            temp != "MD5")
        {
            temp = "SHA1";
        }
        HashAlgorithm hashAlgo = HashAlgorithm.Create(temp);
        if (hashAlgo == null)
            RuntimeConfig.GetAppConfig().Membership.ThrowHashAlgorithmException();
        s_HashAlgorithm = temp;
        return hashAlgo;
    }

经过更多挖掘后,我确定 _LegacyPasswordCompatibilityMode 是从名为 passwordCompatMode 的配置属性中设置的,它属于 SqlMembershipProvider,即使它没有出现在 intellisense 中web.config。一旦我在 web.config 中的 SqlMembershipProvider 上明确设置了 passwordCompatMode="Framework40",我的哈希就开始使用键控 HMACSHA256 哈希,其中键是 machineKey 的 validationKey。使用相同的验证密钥,然后我能够从我的控制台应用程序中重现相同的哈希值。

作为问题的确认,当我删除 passwordCompatMode="Framework40" 属性时,然后在调试器中检查 SqlMembershipProvider 的实例,我可以看到:

_LegacyPasswordCompatibilityMode = "Framework20"
s_HashAlgorithm = "SHA1" (!!!)

这就是疯狂的事情。 SqlMembershipProvider 上的 MSDN 文档指出:

The default value [for passwordCompatMode] is Framework20.

因此,除非您将此模糊属性明确声明为 Framework40,否则 SqlMembershipProvider 使用 SHA1,尽管 4.0 框架被宣传为升级到 HMACSHA256。很难找到推断密钥来自 machineKey 部分的文档……该死的,甚至很难发现 4.0 使用 HMACSHA256,而不仅仅是 SHA256……但我没有看到其他任何地方说明此属性是必需的。我想知道有多少开发人员认为他们使用的是更安全的 HMACSHA[X],而实际上他们仍然只使用 SHA1?希望这对人们有所帮助。

编辑

如果 <membership> 元素未显式声明 hashAlgorithType,则上述内容成立。您可以在上面的 .NET 源代码中看到它查找 !Membership.IsHashAlgorithmFromMembershipConfig,这表明它是否在成员资格元素上找到了 hashAlgorithmType 属性。因此,如果您在配置中指定 <membership ... hashAlgorithmType=[x]>,我相信它不需要 SqlMembershipProvider 上的 passwordCompatMode 属性。