4

今天我将我的 Web 应用程序迁移到 .net 4.0 并且 Forms Auth 刚刚停止工作。经过几个小时的挖掘我的SqlMembershipProvider(内置SqlMembershipProvider的简化版),我发现HMACSHA256哈希并不一致。这是加密方法:

internal string EncodePassword(string pass, int passwordFormat, string salt)
{
    if (passwordFormat == 0) // MembershipPasswordFormat.Clear
        return pass;

    byte[] bIn = Encoding.Unicode.GetBytes(pass);
    byte[] bSalt = Convert.FromBase64String(salt);
    byte[] bAll = new byte[bSalt.Length + bIn.Length];
    byte[] bRet = null;

    Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
    Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
    if (passwordFormat == 1)
    { // MembershipPasswordFormat.Hashed
        HashAlgorithm s = HashAlgorithm.Create( Membership.HashAlgorithmType );
        bRet = s.ComputeHash(bAll);
    } else
    {
        bRet = EncryptPassword( bAll );
    }

    return Convert.ToBase64String(bRet);
}

两次传递相同的密码和盐返回不同的结果!!!它在 .NET 3.5 中运行良好

任何人都知道任何重大更改,还是已知的错误?

更新:当我将 SHA512 指定为散列算法时,一切正常,所以我相信这是在 .NET 4.0 中实现 HMACSHA256 散列算法的错误

谢谢!安德烈

4

2 回答 2

2

我相信 .net 4.0 中已经发生了一些与安全相关的变化,看看这个......

http://www.asp.net/(S(ywiyuluxr3qb2dfva1z5lgeg))/learn/whitepapers/aspnet4/break-changes

突出的第一个明显的事情是......

默认哈希算法现在是 HMACSHA256

ASP.NET 使用加密和散列算法来帮助保护表单身份验证 cookie 和视图状态等数据的安全。默认情况下,ASP.NET 4 现在使用 HMACSHA256 算法对 cookie 和视图状态进行哈希运算。早期版本的 ASP.NET 使用较旧的 HMACSHA1 算法。

如果您运行混合 ASP.NET 2.0/ASP.NET 4 环境,其中表单身份验证 cookie 等数据必须跨 .NET Framework 版本工作,您的应用程序可能会受到影响。要将 ASP.NET 4 Web 应用程序配置为使用旧的 HMACSHA1 算法,请在 Web.config 文件中添加以下设置:

      <machineKey validation="SHA1" />

您是否明确设置了散列算法或只是让 asp.net 决定......如果它现在使用不同的默认值,它可能只是随机抓取任何旧的散列算法,因为不再支持定义的散列算法。

话虽如此,M$ 可能已经淘汰了您正在使用的那个,所以这可能是原因,混蛋....我刚刚意识到我需要测试我的 CMS ...我没有想到。

感谢您的提醒,希望我的想法对我们俩都有帮助!!!

于 2010-05-19T15:57:59.323 回答
2

我也遇到了这个问题。

在我的情况下,最终目标是能够动态设置 connectionString(而不是在 web.config 中硬编码)。为此,我下载了 MS 为 ASP.NET 提供程序提供的源代码,并更改了一些用于获取连接字符串的内部功能。

然而,这都是针对 .NET 2.0 的,看起来就像 Andrey 在上面发布的代码。一切就绪后,我注意到我无法登录我的网站。所以在搜索之后我找到了这个帖子。谢谢!

我继续下载了 .NET Framework 4.0 代码,并且(如果有人想知道)这里是 EncodePassword 方法的新版本。我打算将它复制到我的旧版本的 SqlMembershipProvider 中,这样我就可以使用新的加密方法并能够再次登录到我的 ASP.NET 4.0 网站!

    private string EncodePassword(string pass, int passwordFormat, string salt)
    { 
        if (passwordFormat == 0) // MembershipPasswordFormat.Clear
            return pass;

        byte[] bIn = Encoding.Unicode.GetBytes(pass); 
        byte[] bSalt = Convert.FromBase64String(salt);
        byte[] bRet = null; 

        if (passwordFormat == 1)
        { // MembershipPasswordFormat.Hashed 
            HashAlgorithm hm = GetHashAlgorithm();
            if (hm is KeyedHashAlgorithm) {
                KeyedHashAlgorithm kha = (KeyedHashAlgorithm) hm;
                if (kha.Key.Length == bSalt.Length) { 
                    kha.Key = bSalt;
                } else if (kha.Key.Length < bSalt.Length) { 
                    byte[] bKey = new byte[kha.Key.Length]; 
                    Buffer.BlockCopy(bSalt, 0, bKey, 0, bKey.Length);
                    kha.Key = bKey; 
                } else {
                    byte[] bKey = new byte[kha.Key.Length];
                    for (int iter = 0; iter < bKey.Length; ) {
                        int len = Math.Min(bSalt.Length, bKey.Length - iter); 
                        Buffer.BlockCopy(bSalt, 0, bKey, iter, len);
                        iter += len; 
                    } 
                    kha.Key = bKey;
                } 
                bRet = kha.ComputeHash(bIn);
            }
            else {
                byte[] bAll = new byte[bSalt.Length + bIn.Length]; 
                Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
                Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length); 
                bRet = hm.ComputeHash(bAll); 
            }
        } else { 
            byte[] bAll = new byte[bSalt.Length + bIn.Length];
            Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
            Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
            bRet = EncryptPassword(bAll, _LegacyPasswordCompatibilityMode); 
        }

        return Convert.ToBase64String(bRet); 
    }

编辑:尝试将这一方法复制到旧版本的 SqlMembershipProvider 中是个坏主意。改变太多了。:(

于 2010-08-20T04:18:15.480 回答