2012-08-31 84 views
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

+0

@ ScubaSteve2012盐可以防止预先计算的哈希攻击(“彩虹表”)。由于密码是盐渍的,因此您的彩虹桌无法帮助找出原始密码。你将不得不使用这个哈希创建一个新的彩虹表,这几乎是一个暴力攻击。 – Oleksi

回答

7

您使用PBKDF2-SHA1,这是体面的,但不是很好。 Bcrypt更好一点,而且scrypt更强。但是由于.net已经包含了一个内置的PBKDF2实现,这是一个可以接受的选择。

你最大的错误是你没有得到一个盐的点。盐对每个用户都应该是唯一的。简单地创建至少64位的随机值是标准做法。将它与散列一起存储在数据库中。

如果你愿意,你可以将盐分成两部分。一个存储在用户旁边的数据库中,每个数据都不同,另一个共享部分存储在别处。这获得了两者的优点。

我也推荐使用比1000更高的工作因子。找出可接受的性能,然后进行相应的调整。我不会低于10000,在某些情况下(磁盘加密),也可以接受一百万。

+0

感谢您的帮助。 – ScubaSteve2012

+0

如果盐值存储在数据库中,那么对于防止发现冲突几乎没有帮助。它在这种情况下的主要用途是防止攻击者通过检查发现两个用户具有相同的密码。使用没有明确标记为“盐”的数据会更好,或者甚至更好,但不包含在同一数据存储中的数据;那么攻击者不仅必须危害包含散列的数据库,还要泄露代码库和/或附加的数据存储,以确定如何使用盐以及如何使用。 – KeithS

+0

@KeithS我从来没有提到碰撞这个词,因为碰撞在这里是无关紧要的。盐的主要观点是独特的,从而防止多目标攻击。添加存储在不同位置的秘密是一个很好的额外,但不是盐的主要观点。 – CodesInChaos

5

它可以改进。首先,您应该使用bcrypt。像SHA-512这样的传统哈希现在可以很容易地用GPU来打破。问题是这些散列是为了速度而设计的,而这与密码散列中你想要的相反。 Bcrypt是自适应哈希算法的一个例子。它可以配置为花费很长时间(但仍不会导致系统性能问题)来制造暴力破坏。

您还希望使每个用户的盐都是唯一的。

有关如何安全散列密码的更多信息,请参阅this question

+3

他使用PBKDF2,这比bcrypt差一些,但仍然是推荐的功能之一。 – CodesInChaos

+0

SHA-512字面上“对政府工作而言足够好”;它被认为是密码强大的,并且没有已知的“捷径”降低了找到解决方案的复杂性。任何问题都可以通过投入足够的硬件来“更快”地解决是不相关的;你将不得不尝试5。2 * 10^72的值,然后在* 10亿*的机会中与1之前产生的散列相冲突。 – KeithS

+1

@KeithS Plain SHA-512对密码散列等应用来说不够好,因为它太快了。在密码散列中,您使用故意昂贵的函数来弥补密码中熵的不足。 |另一方面,使用SHA-512的PBKFDF2体面。 – CodesInChaos