当我来到这一部分时,我正在阅读关于散列密码的article:
验证密码
但我对此流程有点困惑,例如假设我有一个带有id,名称,密码和电子邮件的用户表的数据库,为了登录某个应用程序,我需要输入我的电子邮件和密码。
按照上面的步骤,我首先需要获取存储在数据库中的所述用户的salt +哈希密码。
问题:
假设我使用的是一个简单的存储过程,唯一的方法就是这样做......
CREATE PROCEDURE [dbo].[sp_validate_user]
@us_email VARCHAR (MAX)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT us_id,
us_name,
us_pass,
us_email
FROM Users
WHERE us_email = @us_email
END
然后是第二步和第三步:
public static bool ValidatePassword(string inputPassword, string storedPassword)
{
// Extract the parameters from the hash
char[] delimiter = { ':' };
string[] split = storedPassword.Split(delimiter);
int iterations = Int32.Parse(split[ITERATION_INDEX]);
byte[] salt = Convert.FromBase64String(split[SALT_INDEX]);
byte[] hash = Convert.FromBase64String(split[PBKDF2_INDEX]);
byte[] testHash = PBKDF2(inputPassword, salt, iterations, hash.Length);
return SlowEquals(hash, testHash);
}
我担心的是,如果我使用从表中提取的数据创建对象,是否会以某种方式使信息易受攻击?
这也意味着使用此验证的唯一方法是仅根据用户名/电子邮件提取所有用户信息,以便在运行时检查输入密码和散列密码是否匹配,然后让所述用户访问该信息?
如果这听起来令人困惑,我很抱歉,但任何见解都会很棒。
答案 0 :(得分:4)
看起来你可能正在考虑倒退。在传递给哈希函数之前,盐被添加到明文密码中。将最终结果存储在数据库中。
通常,salt是用户名。用户特有的,但用户之间不同,以抵消字典攻击。
因此,对于用户名 u ,密码 p ,假设SHA2是哈希函数。连接 u + p 以获取盐渍值,然后哈希值。
hashtext = SHA2(u + p) // in this case, + is concatenate
hashtext是您存储在数据库中的内容。
登录时,用户输入用户名 u2 和密码 p2 :
tryhash = SHA2(u2 + p2)
查询数据库以查找与u2匹配的用户记录,密码hashtext为 tryhash
假设您有一个接收loginViewModel的MVC操作,该操作填充了从页面输入的明文电子邮件或用户名以及明文密码:
var loginUser = new User(loginViewModel);
CalcHash(loginUser);
var realUser = users.Find(loginUser.username);
if(realUser.HashPassword == loginUser.HashPassword)
// success
虽然也可以将散列密码作为第二个参数添加到数据访问方法中,即。 users.Find(username, hashPass)
,通常不会这样做,因为即使密码失败,您也需要访问用户记录,以增加密码失败次数并锁定帐户。
答案 1 :(得分:1)
本文介绍了ASP.NET(C#)密码哈希码,但您似乎想使用数据库?
你有三件事需要担心;用户的唯一键(用户名),您选择的哈希算法以及在密码尝试中添加盐(防止彩虹表攻击)。
要验证密码,您应该创建一个sql存储过程,该过程接受用户名和密码尝试作为参数。此数据以纯文本格式输入Web表单,传递到Web服务器,并通过存储过程传递到数据库服务器。
存储过程将执行以下操作;
根据用户名参数与用户名字段匹配查找用户的数据行 选择存储的盐场
将(1)中的salt附加到password参数并散列结果
根据username参数与username字段的匹配,查找用户的数据行 和(2)哈希密码字段的哈希结果。
如果找不到行,则密码哈希值不匹配且错误,因此请返回合适的错误代码
如果找到一行,则返回有用的用户数据,即名字,地址
如果存储过程处理了所有这些,那么Web服务器永远不需要知道salt是什么或哈希算法。哈希结果或盐从来没有传输出数据库服务器。
答案 2 :(得分:0)
我认为你理解正确,这是通常的工作流程:
SELECT password_hash FROM user WHERE email=?
获取密码哈希。验证密码无法在单个查询中完成,因为您首先必须提取salt。数据库系统通常不支持适当的散列函数,如 PBKDF2 , BCrypt 或 SCrypt ,因此您必须在代码中进行验证。除了盐之外,您还必须存储其他参数,例如成本因素和算法(以便面向未来),因此最好将所有这些参数存储在同一个数据库字段中。
盐应该是一个至少20个字符的随机字符串,因此不安全将用户名用作salt,或者从其他信息中获取盐。