在对源代码和在线进行更多挖掘之后,我在 SO 上发现了一个问题,用户注意到他/她的 SQLMembershipProvider 哈希在数据库中只有 20 个字节。他们应该是 64 岁。我检查了我的,他们也是。我试图确定一个 SHA256 哈希如何最终只有 20 个字节,并得出结论它不能。所以在我的控制台应用程序中,我尝试只使用 SHA1 来完成它。我将其结果与SQLMembershipProvider 创建的哈希值进行了比较,果然,它匹配!我的 SQLMembershipProvider 使用 SHA1,即使 Membership.HashAlgorithmType 表示它设置为 .NET 4.0 默认值“HMACSHA256”。
这是我阅读源代码的用武之地。我记得我从控制台应用程序中删除了一个条件部分,用于在创建哈希算法类时检查某些旧模式。
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,即使它没有出现在web.config 中的智能感知中。一旦我在 web.config 中的 SqlMembershipProvider 上明确设置了 passwordCompatMode="Framework40",我的哈希就开始使用带密钥的 HMACSHA256 哈希,其中密钥是 machineKey 的验证密钥。使用相同的验证密钥,我就能够从我的控制台应用程序中重现相同的哈希值。
作为对问题的确认,当我删除passwordCompatMode="Framework40" 属性时,然后在调试器中检查SqlMembershipProvider 的实例,我可以看到:
_LegacyPasswordCompatibilityMode = "Framework20"
s_HashAlgorithm = "SHA1" (!!!)
所以这就是疯狂的事情。 SqlMembershipProvider 上的 MSDN 文档指出:
[passwordCompatMode] 的默认值为 Framework20。
因此,除非您将这个晦涩的属性明确声明为 Framework40,否则 SqlMembershipProvider 会使用 SHA1,尽管 4.0 框架被宣传为升级到 HMACSHA256。很难找到推断密钥来自 machineKey 部分的文档......地狱甚至很难找到 4.0 使用 HMACSHA256,而不仅仅是 SHA256......但我没有看到其他任何地方说明这个属性是必需的。我想知道有多少开发人员认为他们使用的是更安全的 HMACSHA[X],而实际上他们仍然只使用 SHA1?希望这对人们有所帮助。
编辑
如果<membership> 元素没有显式声明hashAlgorithType,则上述情况为真。您可以在上面的 .NET 源代码中看到它会查找 !Membership.IsHashAlgorithmFromMembershipConfig,这表明它是否在 member 元素上找到了 hashAlgorithmType 属性。因此,如果您在配置中指定<membership ... hashAlgorithmType=[x]>,我相信它不需要SqlMembershipProvider 上的passwordCompatMode 属性。