我对哈希密码和盐值有所了解。因为我对哈希和加密很新,我想我会把它发给你。为每个用户帐户生成唯一的盐是否更安全,然后在数据库中存储salt和散列值?或者,保持一个盐值安全存储并重新使用,每次我输入密码?
例如, 用户将使用密码:
"secret"
我的代码会生成一个盐值:
"d1d0e3d4b3d1ed1598a4e77bb614750a2a175e"
然后将结果散列为get:
"e8187dcbe8e2eabd4675f3a345fe21c98affb
5544a9278461535cb67265b6fe09a11dbef572
ce3a4a8f2275839927625cf0bc7bc46fc45d51
12d7c0713bb4a3"
散列结果和盐将在创建帐户时存储在用户配置文件的数据库中。然后,每次用户登录时,都会生成一个新的盐,密码和盐重新存储并存储在数据库中。
有什么想法?就像我说的,这是对我的想法的理智检查。
答案 0 :(得分:7)
在我看来,每个用户存储一个独特的盐是个好主意。每次用户登录时重新生成salt / hash组合都是没有意义的,除非你有CPU周期要刻录。我建议使用类似Rfc2898DeriveBytes
类的东西来生成安全的salt / hash组合:
从密码生成哈希的简单示例:
string password = GetPasswordFromInput();
using (var deriveBytes = new Rfc2898DeriveBytes(password, 32)) // 32-byte salt
{
byte[] salt = deriveBytes.Salt;
byte[] hash = deriveBytes.GetBytes(32); // 32-byte hash
SaveToDatabase(salt, hash);
}
并相应检查密码:
string password = GetPasswordFromInput();
byte[] salt = GetSaltFromDatabase();
byte[] hash = GetHashFromDatabase();
using (var deriveBytes = new Rfc2898DeriveBytes(password, salt))
{
if (deriveBytes.GetBytes(32).SequenceEqual(hash))
Console.WriteLine("Password matches");
else
throw new Exception("Bad password");
}
答案 1 :(得分:5)
正如亚当已经提到的,每次用户登录时散列和存储密码都没有用处。
您可能希望研究使用BCrypt.NET(一种经过验证的密码散列算法的.NET实现),而不是自己滚动。
用法非常简单:
// When setting password
string hashedPassword = BCrypt.HashPassword(password, BCrypt.GenerateSalt());
// Upon login
bool validPassword = BCrypt.CheckPassword(password, hashedPassword);
如果您愿意,它允许您改变计算密码哈希的计算成本,使得某人更难以对他们可能获得的数据库进行字典攻击。这是通过向GenerateSalt
方法调用添加参数来完成的。
BCrypt算法的详细信息can be found here。
答案 2 :(得分:3)
salt的目的是防止预计算攻击(例如彩虹表)。因此,如果两个用户具有相同的密码,则它们将不具有相同的最终散列。如果盐是系统范围而不是每个用户,则情况并非如此,攻击者只需要为系统预先计算一次所有密码。如果每个用户都有自己的盐,则需要对每个用户单独进行预计算攻击,使攻击不可行。
使用salted哈希不能防止暴力字典攻击。您需要使用其他方法来防范这些。
答案 3 :(得分:1)
盐的真正目的是防止预计算攻击,因为盐本身不应该是秘密的(即可以从外部世界访问它是好的)。因此,它不打算提供防止暴力强制的安全性,因为它(几乎)很容易哈希(Salt +密码),因为它是哈希(密码)。
如果您认为某人实际上会将您的单一盐的预先计算的表构建到密码数据库中,那么使用所述表查找他们在数据库中找到的盐渍密码哈希值,那么您应该为每个密码使用唯一的盐。否则,不要担心。