【问题标题】:Does salt need to be random to secure a password hash?盐是否需要随机来保护密码哈希?
【发布时间】:2012-02-08 14:54:50
【问题描述】:

我对安全性知之甚少(我需要找到有关基础知识的基本解释),并且正在尝试提出一种合理的方法来使用 .Net 将用户密码存储在数据库中。

这是我目前的解决方案:

private static byte[] HashPassword(string password)
{
   using (var deriveBytes = new Rfc2898DeriveBytes(password, 10))
   {
      byte[] salt = deriveBytes.Salt;
      byte[] key  = deriveBytes.GetBytes(20);

      return salt.Concat(key).ToArray();  //Return Salt+Key
   }
}

我将 HashPassword() 的结果存储在数据库中。 要检查用户的密码,我这样做:

var salt = //1st  10 bytes stored in the DB
var key  = //Next 20 bytes stored in the DB 
using (var deriveBytes = new Rfc2898DeriveBytes(password, salt))
{
   byte[] newKey = deriveBytes.GetBytes(20);

   if (newKey.SequenceEqual(key) == false)  //Check if keys match
   {
      return "No Match";
   }
   else { return "Passwords match"; }

我的问题是盐是否需要像这样随机存储在数据库中,或者我是否可以生成一个 10 字节的盐并将其存储在我的代码中,并始终使用相同的盐来节省自己将盐存储在数据库并只存储密钥?

此外,如果有人发现我正在做的任何其他问题,我将不胜感激任何建议。

【问题讨论】:

标签: security passwords rfc2898


【解决方案1】:

我的问题是盐是否需要像这样随机存储在数据库中,或者我是否可以生成一个 10 字节的盐并将其存储在我的代码中,并始终使用相同的盐来节省自己将盐存储在数据库并只存储密钥?

绝对不是。

如果你问这个问题,你根本不明白盐的用途。

salt 的目的是让攻击者任意更难使用预先计算的散列通用密码表。如果盐总是相同的,那么攻击者只需使用该盐预先计算一个散列的通用密码表。

让我说得更清楚。假设攻击者已经获得了您的密码数据库,并且正在闲暇时对所有存储的散列进行攻击,以计算出与散列对应的密码是什么。如果每个盐都不同,那么攻击者必须对数据库中的每个条目发起新鲜攻击。如果每个盐都相同,那么攻击一个用户会攻击每个用户

此外:假设您为每个用户使用相同的盐。假设两个用户有相同的密码。并且假设攻击者已经获得了密码数据库。 攻击者现在知道哪两个用户有相同的密码,因为他们有相同的加盐哈希,并且可以合理地假设这是数据库中最弱的密码。攻击者可以将她的精力(无论可能是什么)集中在攻击该用户上。一旦她知道该用户的密码,很有可能该用户在其他系统上使用了该用户名和弱密码,攻击者现在可以在获得密码的情况下攻破这些系统文件。

您想了解安全性很好;你试图用你的理解水平编写一个真正的密码系统是很糟糕的。如果这是一个必须保护真实用户的真实系统,use a system built by experts,或聘请您自己的专家。您将创建一个无法破坏的系统,而不是一个攻击者无法破坏的系统。

此外:您在互联网上向陌生人寻求安全方面的帮助。陌生人,你不知道他们是否知道他们在说什么,或者只是在编造一些东西。 找一位真正的安全专家(那是不是我——我是语义分析专家)。构建安全系统是最困难的编程任务之一。你需要专业的帮助。

有关基本密码认证方案的简要介绍,请参阅我的系列文章:

http://blogs.msdn.com/b/ericlippert/archive/tags/salt/

【讨论】:

  • 如果您不想聘请专家,Microsoft 已代表您这样做。使用Membership
  • @Brian:天哪,是的。我没有听说我们已经运送了这个;我已经离开 ASP.NET 循环好几年了。棒极了。如果可能,请务必使用专家编写的现成工具
【解决方案2】:

您不需要应用随机盐,但如果您这样做,您的密码会更加安全。显然,如果您确实应用了随机盐,那么您需要将其与散列密码一起存储在数据库中,以便您可以检查提供的密码。

一个快速的谷歌揭示了this post,这可能会帮助你。

【讨论】:

    最近更新 更多