这是一种安全的密码哈希方式吗?

7

你能否告诉我以下方法是否是安全哈希密码以存储在数据库中的好方法:

    public string CreateStrongHash(string textToHash) {

        byte[] salt =System.Text.Encoding.ASCII.GetBytes("TeStSaLt");

        Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(textToHash, salt, 1000);
        var encryptor = SHA512.Create();
        var hash = encryptor.ComputeHash(k1.GetBytes(16));

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < hash.Length; i++) {
            sb.Append(hash[i].ToString("x2"));
        }

        return sb.ToString();

    }

提前致谢。

4
理想情况下,我认为每个用户应该有一个不同的盐值,并将其存储在数据库中。 - Bridge
1
抱歉如果我有点迟钝,但如果有人获取了数据库访问权限,那么存储盐是否不会使得破解加密更容易? - ScubaSteve2012
@ScubaSteve2012 盐可以防止预先计算的哈希攻击(“彩虹表”)。由于密码被加盐,你的彩虹表在帮助破解原始密码方面将毫无用处。你必须使用这个哈希值创建一个新的彩虹表,这几乎是一种暴力攻击。 - Oleksi
1
@ScubaSteve2012 不,为每个用户使用不同的盐值会使破解加密更加困难,而存储盐并不会使破解加密变得更容易或更难。如果某人获取了数据库访问权限并尝试暴力破解密码,为每个用户使用不同的盐意味着每次暴力攻击只能获得一个密码,而不是所有密码。知道盐的作用不是很大,因为一旦攻击者拥有具有盐的密码,他就知道用户的真正密码是密码+盐组合的子字符串。 - Adam Mihalcin
非常好,谢谢你的解释。现在我明白了。所以如果我将迭代次数增加到10万次,并为每个用户使用一个盐,您认为这样会相当安全吗?还有人建议使用bcrypt,这是否被普遍认同? - ScubaSteve2012
1
你的变量名有些混淆。SHA512不是加密算法,而是哈希算法。 - user395760
2个回答

7
你正在使用PBKDF2-SHA1,这样做还可以但并不是最好的选择。Bcrypt比它更好一些,而scrypt则更加强大。但由于.net已经包含了内置的PBKDF2实现,因此这是一个可接受的选择。
你最大的错误在于没有理解盐的作用。每个用户应该拥有唯一的盐值。通常做法是创建一个至少64位的随机值,并将其与哈希值一起存储到数据库中。
如果需要的话,您可以将盐分为两部分。一部分存储在与用户一起存储在数据库中的独特盐值,另一部分存储在其他地方。这样做可以获得两者的优势。
我也建议使用高于1000的工作因子。可以根据可接受的性能水平进行调整。我不会低于10000,而在某些情况下(如磁盘加密),甚至可以达到1000000。

如果盐值存储在数据库中,那么它对于防止找到碰撞的帮助非常有限。在这种情况下,它的主要作用是防止攻击者通过检查发现两个用户具有相同的密码。最好使用未特别标记为“盐”的数据,甚至更好的是不包含在同一数据存储中;攻击者必须不仅破坏包含哈希的数据库,还必须破坏代码库和/或其他数据存储,以确定用作盐和如何使用。 - KeithS
@KeithS 我从未提到过“碰撞”这个词,因为在这里碰撞是无关紧要的。盐的主要作用是独一无二,从而防止多目标攻击。添加存储在不同位置的秘密是一个不错的额外选择,但并不是盐的主要作用。 - CodesInChaos

5
它可以得到改进。首先,您应该使用 bcrypt 代替。传统哈希函数如 SHA-512 现在可以很容易地被 GPU 破解。问题在于这些哈希函数是为速度而设计的,这与密码哈希所需的相反。Bcrypt 是一种自适应哈希算法的例子。它可以配置为需要“长时间”(但仍不会在系统中引起性能问题)来使暴力破解变得困难。

您还想为每个用户创建唯一的盐。

有关如何安全地哈希密码的更多信息,请参见 this question


3
他正在使用PBKDF2,它比bcrypt差一点,但仍然是推荐的函数之一。 - CodesInChaos
SHA-512在密码学上被视为是具有强加密强度的,而且目前并不存在任何可以简化其解决方案复杂度的“捷径”。任何问题只要投入足够多的硬件资源就能够更快地得到解决这一事实是无关紧要的。因为你需要尝试5.2×10^72个值才有1/十亿的概率与之前生成的哈希发生冲突。因此,SHA-512在实际应用中已经足够安全,即使用于政府级别的工程也毫无压力。 - KeithS
1
@KeithS 简单的SHA-512在像密码哈希这样的应用中并不被认为足够安全,因为它速度太快。在密码哈希中,您使用故意昂贵的函数来弥补密码熵的缺乏。另一方面,PBKFDF2与SHA-512相结合则是相当不错的选择。 - CodesInChaos
在密码哈希中,您应该保护哈希值免受盗窃,并使用唯一的“秘密数据”对每个哈希值进行加盐(例如,能够获取整个数据库的人应该没有盐或不知道盐是什么)。除非攻击者知道如何对其进行加盐(即使代码已混淆,哈希过程也不应在客户端执行),否则加盐会显着增加甚至像“god”和“123”这样的愚蠢密码的熵。 - KeithS
@KeithS 标准假设是盐不是秘密,毕竟你的服务器刚被攻破。有时你会设法保持部分秘密,但通常你不会。盐和密钥强化旨在使密码更难破解,即使你没有对攻击者保守任何秘密。除非应用了显著的强化措施,否则您常见的四个字典单词密码是不安全的。 - CodesInChaos
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接