使用 C# 保护用户密码 - Rfc2898DeriveBytes 与 SHA512
Securing users passwords using c# - Rfc2898DeriveBytes vs SHA512
我一直在阅读有关在数据库中保护用户密码的信息 (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)))
根据这篇文章,这是安全的,但可以通过使用 "key stretching" 更加安全,据我所知,散列算法的速度较慢(使用参数),使暴力破解密码更难。
这就是我所做的:
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。
- 在数据库上 - 我应该将字节数组转换为字符串吗?
这取决于你。字符串更容易处理备份、迁移和调试,而字节数组在数据库中需要更少 space。也许你还应该看看 BCrypt.Net,它生成字符串作为输出,其中包含盐并且很容易存储在单个数据库字段中 [string]。
我一直在阅读有关在数据库中保护用户密码的信息 (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)))
根据这篇文章,这是安全的,但可以通过使用 "key stretching" 更加安全,据我所知,散列算法的速度较慢(使用参数),使暴力破解密码更难。
这就是我所做的:
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。
- 在数据库上 - 我应该将字节数组转换为字符串吗?
这取决于你。字符串更容易处理备份、迁移和调试,而字节数组在数据库中需要更少 space。也许你还应该看看 BCrypt.Net,它生成字符串作为输出,其中包含盐并且很容易存储在单个数据库字段中 [string]。