我试图通过使用散列和加盐将密码保存在数据库中来学习密码学,因此我决定制作一个登录系统以尝试实现该系统。
我的数据库包括
UserID int PK
用户名varchar(250)
盐varbinary(64)
密码varbinary(64)
RegDate日期时间
电子邮件varchar(250)
我正在使用PBKDF2,但似乎这不是哈希/加盐方法,如果不是,该怎么办?
如果是这样,我在这样做吗?
我的钥匙
private const int SALT_SIZE = 64;
private const int KEY_SIZE = 64;
将数据插入数据库
public static void RegisterMe(string _username, string _password, string _email)
{
using (var cn = new SqlConnection(User.strcon))
{
string _sqlins = @"
INSERT INTO
[User]
([Username],[Salt],[Password],[RegDate], [Email])
VALUES
(@Username, @Salt, @Password, CURRENT_TIMESTAMP, @Email)";
var cmd = new SqlCommand(_sqlins, cn);
cn.Open();
using (var deriveBytes = new Rfc2898DeriveBytes(_password, SALT_SIZE))
{
byte[] salt = deriveBytes.Salt;
byte[] key = deriveBytes.GetBytes(KEY_SIZE);
// save salt and key to database
cmd.Parameters.AddWithValue("@Username", _username);
cmd.Parameters.AddWithValue("@Password", key);
cmd.Parameters.AddWithValue("@Salt", salt);
cmd.Parameters.AddWithValue("@Email", _email);
}
cmd.ExecuteNonQuery();
}
}
检查用户是否有效
public bool IsValid(string _email, string _password)
{
using (var cn = new SqlConnection(strcon))
{
byte[] salt = { }, key = { };
string _sql = @"
SELECT
SALT,
[Password],
UserID
FROM
[User]
WHERE [Email] = @email";
SqlCommand cmd = new SqlCommand(_sql, cn);
cmd.Parameters.AddWithValue("@email", _email);
cn.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
{
salt = reader.GetSqlBytes(0).Value;
key = reader.GetSqlBytes(1).Value;
reader.Dispose();
cmd.Dispose();
using (var deriveBytes = new Rfc2898DeriveBytes(_password, salt))
{
byte[] newKey = deriveBytes.GetBytes(KEY_SIZE); // derive a 20-byte key
return newKey.SequenceEqual(key);
}
}
else
{
reader.Dispose();
cmd.Dispose();
return false;
}
}
}
我的系统正常工作,它将数据以字节为单位设置到数据库中,如果用户键入正确的密码,它将返回true。但这是正确的方法吗?这甚至是哈希/盐腌吗?
最佳答案
您基本上是朝着正确的方向前进,但我会指出一些要考虑的事项:
PBKDF2方法的默认迭代次数可能不够,并且您可能不想将其保留为默认值。我建议将迭代次数指定为至少10K。
另一方面,此实现以字节为单位计算密钥大小和盐大小。 64字节有点太多。将两者都保留为16个字节应足够。不建议超过20个字节,因为这是基础哈希函数/ HMAC的最大大小。这样做只会给攻击者带来好处(很多人认为,这是PBKDF2中的一个设计错误)。当然,您可以将varbinary的大小设置为较高的值,以便将来进行升级。
建议您保留带有盐和哈希密码的协议编号。这样做使您可以在以后可以按用户每次重设密码的日期和方案进行升级。
小点; MSDN没有指定何时生成盐。我将检查盐的随机性(检查每次是否不同),并且仅在调用getBytes
之后询问盐,以确保盐的确确实是随机的,即使实现发生了变化。否则,请使用加密安全的随机数生成器自己生成它。
关于c# - 用PBKDF2腌制和散列,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23169359/