.NET 4.0 中的错误加密错误

发布于 2024-09-01 12:28:46 字数 1107 浏览 12 评论 0原文

今天,我将 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 哈希算法实现中的一个错误,

谢谢! 安德烈

Today I moved my web application to .net 4.0 and Forms Auth just stopped working. After several hours of digging into my SqlMembershipProvider (simplified version of built-in SqlMembershipProvider), I found that HMACSHA256 hash is not consistent. This is the encryption method:

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);
}

Passing the same password and salt twice returns different results!!! It was working perfectly in .NET 3.5

Anyone aware of any breaking changes, or is it a known bug?

UPDATE: When I specify SHA512 as hashing algorithm, everything works fine, so I do believe it's a bug in implementation of HMACSHA256 hashing algorithm in .NET 4.0

Thanks!
Andrey

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

旧人哭 2024-09-08 12:28:47

我相信 .net 4.0 中存在一些与安全相关的更改,看看这个...

http://www.asp.net/(S(ywiyuluxr3qb2dfva1z5lgeg))/learn/whitepapers/aspnet4/writing-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$ 可能已经退役了您正在使用的那个,所以这可能就是原因,bugger....我刚刚意识到我需要测试我的 CMS...我没有想到这一点。

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

I believe there have been some security related changes in .net 4.0 have a look at this ...

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

The first obvious thing that sticks out is this ...

Default Hashing Algorithm Is Now
HMACSHA256

ASP.NET uses both encryption and
hashing algorithms to help secure data
such as forms authentication cookies
and view state. By default, ASP.NET 4
now uses the HMACSHA256 algorithm for
hash operations on cookies and view
state. Earlier versions of ASP.NET
used the older HMACSHA1 algorithm.

Your applications might be affected if
you run mixed ASP.NET 2.0/ASP.NET 4
environments where data such as forms
authentication cookies must work
across.NET Framework versions. To
configure an ASP.NET 4 Web application
to use the older HMACSHA1 algorithm,
add the following setting in the
Web.config file:

      <machineKey validation="SHA1" />

Have you explicitly set your hashing algorithm or just let asp.net decide ... if it's using a different default now it may be just grabbing any old hashing algorithm at random as the defined one is no longer supported.

Having said that, M$ may have retired the one you are using, so that may be the cause, bugger .... i just realised i need to test my CMS ... this hadn't occurred to me.

Thanks for the heads up, hopefully my thoughts will help us both !!!

无人问我粥可暖 2024-09-08 12:28:47

我也遇到了这个问题。

在我的情况下,最终目标是能够动态设置连接字符串(而不是在 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 中是一个坏主意。改变太多了。 :(

I also ran into this problem.

In my situation the end goal was to be able to set the connectionString dynamically (instead of hard-coded in the web.config). I did this by downloading the source code MS has put out for the ASP.NET Providers and changing some of the internal functionality for getting the connection string.

However, this was all for .NET 2.0 and looks just like the code Andrey posted up above. Once I got it all in place, I noticed I was unable to login to my website. So after searching I found this post. Thanks!

I went ahead and downloaded the .NET Framework 4.0 code and (if anyone wants to know) here is the new version of the EncodePassword method. I'm planning to copy this into my old version of the SqlMembershipProvider so I can use the new encryption methods and be able to login to my ASP.NET 4.0 website again!

    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); 
    }

Edit: Attempting to copy this one method into the old version of the SqlMembershipProvider was a bad idea. Too much has changed. :(

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文