将散列密码存储为UTF8字符串的含义?

时间:2014-01-18 09:40:41

标签: c# .net utf-8 passwords md5

我发现以下代码用于在将密码存储到MSSQL数据库之前对其进行哈希处理(该列的类型为NVARCHAR)。

string HashPassword(string password)
{
    var encoding = Encoding.UTF8,
    var plainBytes = encoding.GetBytes(password);
    var hashedBytes = MD5.Create().ComputeHash(plainBytes);
    return encoding.GetString(hashedBytes); //<-- Bad practice?
}

起初我认为尝试将随机字节存储为UTF8字符串并且我应该将其更改为Base64编码真的很奇怪。但除了不良做法之外,这样做有什么实际意义吗?

还;如果有人拿到了数据库,这是不是意味着不可能使用彩虹表或类似的方法来尝试并反驳哈希值,因为原始字节丢失了?

2 个答案:

答案 0 :(得分:5)

您通过减少将要编码的可能字符串的数量来削弱安全性。每当你的哈希最终成为无效的UTF-8序列时,你最终会以U + FFFD作为输出字符(Unicode&#34;替换&#34;字符)。这意味着多个哈希以相同的字符串结束:

using System;
using System.Text;

class Program
{
    static void Main(string[] args)
    {
        byte[] hash1 = FillBytes(128);
        byte[] hash2 = FillBytes(129);
        string text1 = Encoding.UTF8.GetString(hash1);
        string text2 = Encoding.UTF8.GetString(hash2);
        Console.WriteLine(text1 == text2);
    }

    static byte[] FillBytes(byte data)
    {
        byte[] bytes = new byte[16];
        for (int i = 0; i < bytes.Length; i++)
        {
            bytes[i] = data;
        }
        return bytes;
    }
}

GetString返回的文本也可能无法正确存储在SQL Server中,具体取决于您配置的方式。 (如果字段设置为可以存储任何Unicode格式,那部分就可以了。)如果 丢失数据,那就更糟了 - 存储正确哈希不匹配计算正确哈希,因此输入正确密码的人仍将被拒绝访问。正如我所说,这可能不是问题 - 但你还没有给我们足够的信息来肯定地说,所以它至少值得考虑。如果使用Base64或hex,这部分将不会成为问题,两者都以ASCII数据结束。

使用MD5来对密码进行哈希处理是个不错的主意 - 通过有损文本转换来削弱它更进一步更糟糕。它使攻击者更容易找到仍然以相同文本结尾的错误密码。

我建议:

  • 您使用更安全的哈希方法(例如bcrypt或PBKDF2) - 有关更多详细信息,请参阅Jeff Atwood's blog post(并阅读更多安全手册)
  • 要存储哈希,请使用blob(直接存储字节)或转换为base64或hex,以保留完整信息。

答案 1 :(得分:0)

这可能有用,但这确实是一种不好的做法。至少转换将取决于当地的字符集。