在将密码存储在数据库中时,您应该始终在散列之前对密码进行加盐。
推荐的数据库列:
您在网上找到的大多数帖子都会讨论 ASCII 编码盐和哈希,但这不是必需的,只会增加不必要的计算。此外,如果您使用 SHA-1,则输出将只有 20 个字节,因此您在数据库中的哈希字段长度只需 20 个字节。我理解您对 SHA-256 的询问,但除非您有令人信服的理由,否则在大多数业务实践中使用带有盐值的 SHA-1 就足够了。如果你坚持使用SHA-256,那么数据库中的hash字段长度需要为32字节。
以下是一些函数,它们将生成盐、计算哈希并根据密码验证哈希。
下面的 salt 函数从 4 个以加密方式创建的随机字节生成一个加密强的 salt 作为整数。
private int GenerateSaltForPassword()
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] saltBytes = new byte[4];
rng.GetNonZeroBytes(saltBytes);
return (((int)saltBytes[0]) << 24) + (((int)saltBytes[1]) << 16) + (((int)saltBytes[2]) << 8) + ((int)saltBytes[3]);
}
然后可以使用带有以下功能的盐对密码进行哈希处理。盐与密码连接,然后计算哈希。
private byte[] ComputePasswordHash(string password, int salt)
{
byte[] saltBytes = new byte[4];
saltBytes[0] = (byte)(salt >> 24);
saltBytes[1] = (byte)(salt >> 16);
saltBytes[2] = (byte)(salt >> 8);
saltBytes[3] = (byte)(salt);
byte[] passwordBytes = UTF8Encoding.UTF8.GetBytes(password);
byte[] preHashed = new byte[saltBytes.Length + passwordBytes.Length];
System.Buffer.BlockCopy(passwordBytes, 0, preHashed, 0, passwordBytes.Length);
System.Buffer.BlockCopy(saltBytes, 0, preHashed, passwordBytes.Length, saltBytes.Length);
SHA1 sha1 = SHA1.Create();
return sha1.ComputeHash(preHashed);
}
只需计算哈希值,然后将其与预期的哈希值进行比较,即可检查密码。
private bool IsPasswordValid(string passwordToValidate, int salt, byte[] correctPasswordHash)
{
byte[] hashedPassword = ComputePasswordHash(passwordToValidate, salt);
return hashedPassword.SequenceEqual(correctPasswordHash);
}