我一直在阅读有关保护数据库中用户密码的信息(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)))
根据这篇文章,这是安全的,但通过使用“键扩展”可以更加安全,据我所知,“键扩展”是散列,散列的执行速度较慢(使用参数),从而使暴力破解密码变得更困难.
所以这就是我所做的:
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);
现在这是我的问题:
> SHA512和Rfc2898DeriveBytes有什么区别?哪个更安全?
>是否应该在迭代中增加盐分?会使其更安全吗?
>在1000次迭代中,它运行非常快-应该慢多少?半秒钟?一秒?这里的经验法则是什么?
>在数据库上-我应该将字节数组转换为字符串并存储字符串,还是应该将字节数组存储在二进制数据字段中?
编辑(另一个问题)
>如果我在重新哈希处理SHA512上迭代了1000次,它是否具有相同的安全性?
解决方法:
> SHA512和Rfc2898DeriveBytes有什么区别?
SHA512是加密哈希函数,而Rfc2898DeriveBytes是密钥派生函数.就像您已经写过的那样,哈希函数太快了,太容易被暴力破解了,这就是为什么我们需要具有成本因素的函数,如BCrypt,SCrypt,PBKDF2或Argon2.据我所知,Rfc2898DeriveBytes使用带有SHA1的HMAC来实现PBKDF2.这回答了您的另一个问题,即迭代的SHA不如Rfc2898DeriveBytes安全.
>是否应该在迭代中增加盐分?
盐和成本因素无关,用途不同.盐防止使用彩虹表,迭代是针对暴力攻击的对策.您可以从我的tutorial获取更多有关安全密码存储的信息.所以不,不要使盐变短.
>应该多慢?
当然,这取决于您的服务器和对安全性的要求,速度越慢意味着越难以暴力破解.根据经验,单个哈希值约为50 milliseconds.
>在数据库上-我应该将字节数组转换为字符串吗?
这取决于你.字符串更易于处理以进行备份,迁移和调试,而字节数组则需要较少的数据库空间.也许您还应该看看BCrypt.Net,它会生成包含盐的字符串作为输出,并且易于存储在单个数据库字段[string]中.