我正在尝试使用c#创建和测试我的api登录。下面是代码的主要部分:
private static void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] passwordSalt)
{
using (var hmac = new HMACSHA512())
{
passwordSalt = hmac.Key;
passwordHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
}
}
private static bool VerifyPasswordHash(string password, byte[] passwordHash, byte[] passwordSalt)
{
using (var hmac = new HMACSHA512(passwordSalt))
{
var computedHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
return computedHash.SequenceEqual(passwordHash);
}
}
我的数据库是Mysql 8与字符集utf8mb4整理utf8mb4_unicode_520_ci格式。值被存储为varchar(512),因此在保存时长度不是问题。
用于保存数据的DB部分的代码为:
Cmd.Parameters.Add(new MySqlParameter("@username", MySqlDbType.VarChar)).Value = user.UserName;
Cmd.Parameters.Add(new MySqlParameter("@passwordhash", MySqlDbType.VarChar)).Value = Convert.ToBase64String(user.PasswordHash);
Cmd.Parameters.Add(new MySqlParameter("@passwordsalt", MySqlDbType.VarChar)).Value = Convert.ToBase64String(user.PasswordSalt);
从数据库中检索数据进行密码检查的代码为:
while (Rdr.Read() == true)
{
user.UserName = Rdr.GetString("username");
user.PasswordHash = System.Text.Encoding.UTF8.GetBytes(Rdr.GetString("passwordhash"));
user.PasswordSalt = System.Text.Encoding.UTF8.GetBytes(Rdr.GetString("passwordsalt"));
user.UserID = Rdr.GetInt16("userid");
}
Rdr.Close();
然而,当我做密码匹配,它总是不匹配,你能帮我我做错了,是在编码等。
VerifyPasswordHash(request.Password, user.PasswordHash, user.PasswordSalt)
从教程中学习代码,但教程是从DB提取的,所以想知道我在这个过程中是否做错了什么,因为它不匹配。
我认为你需要使用Convert.FromBase64String
转换回哈希和盐。
while (Rdr.Read() == true)
{
user.UserName = Rdr.GetString("username");
user.PasswordHash = Convert.FromBase64String(Rdr.GetString("passwordhash"));
user.PasswordSalt = Convert.FromBase64String(Rdr.GetString("passwordsalt"));
user.UserID = Rdr.GetInt16("userid");
}
Rdr.Close();
这是存储密码哈希的错误方法,它可以在普通硬件上计算得太快(每秒几千兆SHA512)。因此,您需要像BCrypt或Argon2这样的密码哈希函数,它们具有成本因子来控制单个计算所需的时间。
BCrypt库https://www.nuget.org/packages/BCrypt.Net-Next/是个不错的选择。它还将盐包含/提取到结果密码哈希字符串中,因此您只需要一个db字段来存储哈希值。