代码之家  ›  专栏  ›  技术社区  ›  Andrey

.NET 4.0中的加密错误

  •  4
  • Andrey  · 技术社区  · 16 年前

    今天我将我的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);
    }
    

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

    是否有人知道任何破坏性的更改,或者它是已知的错误?

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

    谢谢! 安德烈

    2 回复  |  直到 15 年前
        1
  •  2
  •   War    16 年前

    我相信.NET 4.0中有一些与安全相关的更改,请看一下…

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

    最明显的是…

    默认哈希算法现在为 HMACHA256

    ASP.NET同时使用加密和 哈希算法有助于保护数据 例如窗体身份验证cookie 和查看状态。默认情况下,ASP.NET 4 现在使用hmacsha256算法 对cookie和视图执行哈希操作 状态。早期版本的ASP.NET 使用了旧的hmacsha1算法。

    如果 运行混合的ASP.NET 2.0/ASP.NET 4 数据(如表单)所在的环境 身份验证cookie必须工作 跨.NET框架版本。到 配置ASP.NET 4 Web应用程序 要使用旧的hmacsha1算法, 在中添加以下设置 web.config文件:

          <machineKey validation="SHA1" />
    

    您是否已显式设置了哈希算法或让ASP.NET决定…如果它现在使用不同的默认值,它可能只是随机地获取任何旧的散列算法,因为不再支持所定义的散列算法。

    这么说来,M$可能已经使你使用的那个失效了,所以这可能就是原因,Bugger…。我刚刚意识到我需要测试我的CMS…我没有想到这一点。

    谢谢你的提醒,希望我的想法能帮助我们俩!!!!

        2
  •  2
  •   Jason    15 年前

    我也遇到了这个问题。

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

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

    我继续下载了.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中是一个坏主意。变化太多了。:(

    推荐文章