使用C#保护用户密码-Rfc2898DeriveBytes与SHA512

dev*_*r82 4 c# security passwords hash salt

我一直在阅读有关保护数据库中用户密码的信息(https://crackstation.net/hashing-security.htm)。基本概念已被理解-生成一个随机的Salt,将其附加到密码并哈希密码。

所以这就是我所做的(我没有在这里放一些可以转换为字符串的方法):

RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create();
byte[] rndBytes = new byte[512];
randomNumberGenerator.GetBytes(rndBytes);
string salt = ToHexString(rndBytes);

var sha512Hasher = SHA512.Create();
string hashedPwd = ToHexString(sha512Hasher.ComputeHash(GetBytes(pwd + salt)))
Run Code Online (Sandbox Code Playgroud)

根据这篇文章,这是安全的,但通过使用“键扩展”可以更加安全,据我所知,“键扩展”对哈希的执行速度较慢(使用参数),使暴力破解密码的难度加大。

所以这就是我所做的:

RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create();
byte[] salt = new byte[512];
randomNumberGenerator.GetBytes(salt);
Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(user.Password, salt, 1000);
byte[] hashBytes = k1.GetBytes(512);
string hash = ToHexString(hashBytes);
Run Code Online (Sandbox Code Playgroud)

现在这是我的问题:

  1. SHA512和之间有什么区别Rfc2898DeriveBytes?哪个更安全?
  2. 我应该在迭代中增加盐分吗?会使其更安全吗?
  3. 在1000次迭代中,它运行得非常快-应该慢多少?半秒钟?一秒?这里的经验法则是什么?
  4. 在数据库上-我应该将字节数组转换为字符串并存储字符串,还是应该将字节数组存储在二进制数据字段中?

编辑(另一个问题)

  1. 如果我在重新哈希处理SHA512上迭代了1000次-它是否具有相同的安全性?

mar*_*kli 5

  1. SHA512和Rfc2898DeriveBytes有什么区别?

SHA512是加密哈希函数,而Rfc2898DeriveBytes是密钥派生函数。就像您已经写过的那样,哈希函数太快了,太容易被暴力破解了,这就是为什么我们需要具有成本因素的函数,例如BCrypt,SCrypt,PBKDF2或Argon2。据我所知,Rfc2898DeriveBytes使用带有SHA1的HMAC来实现PBKDF2。这回答您的其他问题,一个迭代SHA是比Rfc2898DeriveBytes安全。

  1. 我应该在迭代中增加盐分吗?

盐和成本因素无关,用途不同。盐防止使用彩虹表,迭代是针对暴力攻击的对策。您可以从我的教程中获得有关安全密码存储的更多信息。所以不,不要使盐变短。

  1. 应该有多慢?

当然,这取决于您的服务器和对安全性的要求,速度越慢意味着越难以暴力破解。单个哈希的经验法则大约为50毫秒

  1. 在数据库上-我应该将字节数组转换为字符串吗?

这取决于你。字符串更易于处理以进行备份,迁移和调试,而字节数组则需要较少的数据库空间。也许您还应该看看BCrypt.Net,它会生成包含盐的字符串作为输出,并且易于存储在单个数据库字段[string]中。