C# 使用Razor MVC+进行用户身份验证;Mysql
我试图为Mysql数据库中存储的用户/密码编写一个简单的身份验证函数。问题是我对c#还不熟悉,所以请原谅我的代码片段中可能出现的任何缺陷。到目前为止,我得到的是: 用户注册(已测试并将记录保存到数据库): 和用户验证(我认为这不太正确) 再次感谢您的帮助。谢谢 我试图为Mysql数据库中存储的用户/密码编写一个简单的身份验证函数 首先,一些互联网/编程点会出现在你面前;查看在存储密码时使用哈希的机会。当我得知人们/公司以明文形式存储密码或只是使用加密(谁付钱给这些人?)时,这对我来说是一个重大的细微差别C# 使用Razor MVC+进行用户身份验证;Mysql,c#,mysql,asp.net-mvc,razor,C#,Mysql,Asp.net Mvc,Razor,我试图为Mysql数据库中存储的用户/密码编写一个简单的身份验证函数。问题是我对c#还不熟悉,所以请原谅我的代码片段中可能出现的任何缺陷。到目前为止,我得到的是: 用户注册(已测试并将记录保存到数据库): 和用户验证(我认为这不太正确) 再次感谢您的帮助。谢谢 我试图为Mysql数据库中存储的用户/密码编写一个简单的身份验证函数 首先,一些互联网/编程点会出现在你面前;查看在存储密码时使用哈希的机会。当我得知人们/公司以明文形式存储密码或只是使用加密(谁付钱给这些人?)时,这对我来说是一个重大的
下面,我概述了在存储和检索散列密码时需要考虑的要点。
如何存储哈希密码:
这是我在数据库中存储密码的唯一方法-我知道可能还有其他方法-请不要判断 <>在数据库中存储<代码>用户< /代码>时需要考虑的3件事:
...
var salt = Crypto.GenerateSalt();
sha256 = Crypto.SHA256(user.password);
password = Crypto.HashPassword(salt + sha256);
string sql = "INSERT INTO user(last_name ,first_name, email, password, salt, city_id) "
+ "VALUES (?lastName,?firstName,?email,?password,?salt,?cityId); "; // Add 'salt' in here
MySqlCommand cmd = new MySqlCommand(sql, conn);
cmd.Prepare();
// ...
cmd.Parameters.Add("?password", MySqlDbType.VarChar).Value = password;
cmd.Parameters.Add("?salt", MySqlDbType.VarChar).Value = salt; // Save the 'salt' value
...
var actualHash = user.password; // Get the hashed password from the DB
if (loginPasswordHash == actualHash)
{
// Password is correct
}
else
{
// Password was incorrect
}
- 存储
,以便以后检索盐
- 了解您用于连接输入密码和salt以首先生成哈希的确切模式(例如,
)salt+inputPassword
- 存储
,以便以后检索哈希密码
密码进行哈希运算时,生成Salt
的想法是正确的。唯一的问题是,您实际上并没有将其存储在任何地方—这对于验证用户的凭据是必不可少的
更多关于这一点,见下文
如何检索密码?:
我相信您已经知道,关于用户密码的唯一信息是它的散列,您已经保存在数据库中。再加上随机生成的salt,您就拥有了一个非常安全的密码
还记得我说过的关于在数据库中存储盐的观点吗;还记得你是如何把这个Salt
和原来的密码
放在一起的吗?这就是你需要的地方
检查登录密码和存储密码是否匹配的唯一方法是运行与创建用户时相同的过程。除此之外,这次不生成新的Salt
;您使用数据库中针对用户存储的一个(这就是我们存储它的原因)
像这样:
- 首先,验证用户是否确实存在于数据库中(有点明显),并根据他们检索数据
- 使用他们存储的
Salt
,将其与他们输入的密码连接起来,方法与生成哈希时的方法相同(在上面的示例中,我使用了Salt+inputPassword
,因此我们将使用此方法)
- 然后,您可以基于此连接生成哈希:
var loginPasswordHash=Crypto.HashPassword(salt+inputPassword)代码>
- 如果您使用的方法与第一次用于生成哈希的方法完全相同,则
loginPasswordHash
应该与数据库中的方法完全相同(只要正确)-例如If(loginPasswordHash==storedPasswordHash)
- 你可以对此进行检查,如果他们匹配,那么你就知道他们的密码是正确的;否则,你知道这是错误的
与加密(可逆且使用私钥)或纯文本(到底是什么?)不同,您永远无法仅从salt和hash中找到原始密码。
除非你不使用salt,否则使用一些非常整洁的rainbow查找表可以获得密码——哈希可能只有一种方式,但每次都会生成相同的最终结果
如何在代码中应用上述原则:
首先,在创建用户时,您当前没有将生成的salt存储在数据库中
去做吧
您将需要在MySQL表中为Salt
添加一个新列。创造它
SaveUser
在SaveUser
方法中,还要确保将生成的salt
保存在数据库中:
...
var salt = Crypto.GenerateSalt();
sha256 = Crypto.SHA256(user.password);
password = Crypto.HashPassword(salt + sha256);
string sql = "INSERT INTO user(last_name ,first_name, email, password, salt, city_id) "
+ "VALUES (?lastName,?firstName,?email,?password,?salt,?cityId); "; // Add 'salt' in here
MySqlCommand cmd = new MySqlCommand(sql, conn);
cmd.Prepare();
// ...
cmd.Parameters.Add("?password", MySqlDbType.VarChar).Value = password;
cmd.Parameters.Add("?salt", MySqlDbType.VarChar).Value = salt; // Save the 'salt' value
...
var actualHash = user.password; // Get the hashed password from the DB
if (loginPasswordHash == actualHash)
{
// Password is correct
}
else
{
// Password was incorrect
}
认证者
在AuthenticateUser
方法中,从数据库中检索已知的用户
详细信息,以检查身份验证
然后,使用与生成要存储在数据库中的密码
散列时相同的方法,您可以使用此方法生成另一个要在登录时检查的散列:
var salt = user.salt; // Salt from the DB
sha256 = Crypto.SHA256(login.password); // Hash their input password
loginPasswordHash = Crypto.HashPassword(salt + sha256); // Generate a hash of this, just like you did when creating the user
然后,您只需对数据库中的密码进行检查:
...
var salt = Crypto.GenerateSalt();
sha256 = Crypto.SHA256(user.password);
password = Crypto.HashPassword(salt + sha256);
string sql = "INSERT INTO user(last_name ,first_name, email, password, salt, city_id) "
+ "VALUES (?lastName,?firstName,?email,?password,?salt,?cityId); "; // Add 'salt' in here
MySqlCommand cmd = new MySqlCommand(sql, conn);
cmd.Prepare();
// ...
cmd.Parameters.Add("?password", MySqlDbType.VarChar).Value = password;
cmd.Parameters.Add("?salt", MySqlDbType.VarChar).Value = salt; // Save the 'salt' value
...
var actualHash = user.password; // Get the hashed password from the DB
if (loginPasswordHash == actualHash)
{
// Password is correct
}
else
{
// Password was incorrect
}
最后一个注释:
最后一件我一直很挑剔的事情就是这个
当尝试登录时,用户名和/或密码不正确,您会显示什么
我建议显示一个错误,并且只显示一个错误:
“您提供的登录凭据不正确”
这有助于抵御那些想首先检查潜在用户名有效性的潜在黑客
这是一段漫长的旅程
不过,我希望这对您的项目有所帮助:)
问候,,
杰夫
更新
尽管上面的例子和对话概括了你最初问题的答案;这要感谢@zaph指出散列的安全性:
这是不安全的,散列必须迭代以需要最少的CPU时间。用随机盐在HMAC上迭代约100ms d