【问题标题】:Is there a bug in the hashfunction of the ASP.NET DefaultMembershipProvider?ASP.NET DefaultMembershipProvider 的哈希函数中是否存在错误?
【发布时间】:2013-10-03 15:19:32
【问题描述】:

我正在迁移我的旧 ASP.NET Webforms 应用程序以开始使用 ASP.NET 内置 DefaultMembershipProvider。我的旧自制身份验证模块用于存储密码的 SHA256 哈希值。我认为“升级”到 DefaultMembershipProvider,它也在 SQL DB 中存储散列,这意味着我也可以迁移这些散列,因此为当前用户提供无痛升级(这样他们就不必重置密码)。

现在,这并没有按计划工作(显然!),我开始研究 DefaultMembershipProvider 的来源(更具体地说,就在这里:https://github.com/wyxy2005/bluceNet/tree/master/System.Web.Providers),我遇到了以下函数:

private string EncodePassword(string pass, int passwordFormat, string salt)
    {
        if (passwordFormat == 0)
        {
            return pass;
        }
        byte[] bytes = Encoding.Unicode.GetBytes(pass);
        byte[] src = Convert.FromBase64String(salt);
        byte[] inArray = null;
        if (passwordFormat == 1)
        {
            HashAlgorithm hashAlgorithm = this.GetHashAlgorithm();
            KeyedHashAlgorithm algorithm2 = hashAlgorithm as KeyedHashAlgorithm;
            if (algorithm2 != null)
            {
                if (algorithm2.Key.Length == src.Length)
                {
                    algorithm2.Key = src;
                }
                else if (algorithm2.Key.Length < src.Length)
                {
                    byte[] dst = new byte[algorithm2.Key.Length];
                    Buffer.BlockCopy(src, 0, dst, 0, dst.Length);
                    algorithm2.Key = dst;
                }
                else
                {
                    int num2;
                    byte[] buffer5 = new byte[algorithm2.Key.Length];
                    for (int i = 0; i < buffer5.Length; i += num2)
                    {
                        num2 = Math.Min(src.Length, buffer5.Length - i);
                        Buffer.BlockCopy(src, 0, buffer5, i, num2);
                    }
                    algorithm2.Key = buffer5;
                }
                inArray = algorithm2.ComputeHash(bytes);
            }
            else
            {
                byte[] buffer6 = new byte[src.Length + bytes.Length];
                Buffer.BlockCopy(src, 0, buffer6, 0, src.Length);
                Buffer.BlockCopy(bytes, 0, buffer6, src.Length, bytes.Length);
                inArray = hashAlgorithm.ComputeHash(buffer6);
            }
        }
        else
        {
            byte[] buffer7 = new byte[src.Length + bytes.Length];
            Buffer.BlockCopy(src, 0, buffer7, 0, src.Length);
            Buffer.BlockCopy(bytes, 0, buffer7, src.Length, bytes.Length);
            inArray = this.EncryptPassword(buffer7, this.LegacyPasswordCompatibilityMode);
        }
        return Convert.ToBase64String(inArray);
    }

现在,在我的特定场景中,我没有任何密码盐,因为我的旧身份验证模块没有使用它,所以 string salt 是空的,byte [] src 也是空的。默认使用的散列算法是 HMACSHA256,它是一个键控散列函数。所以我们进入了这个for循环,其中num2总是 0。由于num2也被用作增量器,我们进入了一个无限循环。

算法不应该针对这种特殊情况进行测试吗?这不应该是一个简单的错误,只需对代码进行单元测试就可以捕获吗?还是我忽略了什么?

【问题讨论】:

    标签: c# asp.net hash webforms asp.net-membership


    【解决方案1】:

    我不是安全专家,因此无法回答您的问题。

    这是新ASP.Net Universal Provider 使用的EncodePassword 方法。

    它与旧的 MembershipProvider 有点不同。您可能想尝试一下。

    private string EncodePassword(string pass, int passwordFormat, string salt)
    {
        byte[] numArray;
        byte[] numArray1;
        string base64String;
        bool length = passwordFormat != 0;
        if (length)
        {
            byte[] bytes = Encoding.Unicode.GetBytes(pass);
            byte[] numArray2 = Convert.FromBase64String(salt);
            byte[] numArray3 = null;
            length = passwordFormat != 1;
            if (length)
            {
                numArray1 = new byte[(int)numArray2.Length + (int)bytes.Length];
                Buffer.BlockCopy(numArray2, 0, numArray1, 0, (int)numArray2.Length);
                Buffer.BlockCopy(bytes, 0, numArray1, (int)numArray2.Length, (int)bytes.Length);
                numArray3 = this.EncryptPassword(numArray1);
            }
            else
            {
                HashAlgorithm hashAlgorithm = this.GetHashAlgorithm();
                length = hashAlgorithm as KeyedHashAlgorithm <= null;
                if (length)
                {
                    numArray1 = new byte[(int)numArray2.Length + (int)bytes.Length];
                    Buffer.BlockCopy(numArray2, 0, numArray1, 0, (int)numArray2.Length);
                    Buffer.BlockCopy(bytes, 0, numArray1, (int)numArray2.Length, (int)bytes.Length);
                    numArray3 = hashAlgorithm.ComputeHash(numArray1);
                }
                else
                {
                    KeyedHashAlgorithm keyedHashAlgorithm = (KeyedHashAlgorithm)hashAlgorithm;
                    length = (int)keyedHashAlgorithm.Key.Length != (int)numArray2.Length;
                    if (length)
                    {
                        length = (int)keyedHashAlgorithm.Key.Length >= (int)numArray2.Length;
                        if (length)
                        {
                            numArray = new byte[(int)keyedHashAlgorithm.Key.Length];
                            int num = 0;
                            while (true)
                            {
                                length = num < (int)numArray.Length;
                                if (!length)
                                {
                                    break;
                                }
                                int num1 = Math.Min((int)numArray2.Length, (int)numArray.Length - num);
                                Buffer.BlockCopy(numArray2, 0, numArray, num, num1);
                                num = num + num1;
                            }
                            keyedHashAlgorithm.Key = numArray;
                        }
                        else
                        {
                            numArray = new byte[(int)keyedHashAlgorithm.Key.Length];
                            Buffer.BlockCopy(numArray2, 0, numArray, 0, (int)numArray.Length);
                            keyedHashAlgorithm.Key = numArray;
                        }
                    }
                    else
                    {
                        keyedHashAlgorithm.Key = numArray2;
                    }
                    numArray3 = keyedHashAlgorithm.ComputeHash(bytes);
                }
            }
            base64String = Convert.ToBase64String(numArray3);
        }
        else
        {
            base64String = pass;
        }
        return base64String;
    }
    

    【讨论】:

    • 当 salt 为空字符串时,此函数会遇到同样的无限循环问题。在这种情况下,'num' 永远不会大于零,因此 while 循环永远不会中断......
    • 您能否提供有关 this.GetHashAlgorithm() 和 this.EncryptPassword(numArray1) 方法的更多信息 - 谢谢
    猜你喜欢
    • 2015-07-04
    • 2015-02-21
    • 2012-09-03
    • 2011-05-19
    • 2015-06-22
    • 2017-01-22
    • 2011-02-04
    • 2013-12-23
    • 1970-01-01
    相关资源
    最近更新 更多