当我进入这一部分时,我正在阅读有关散列密码的文章:
验证密码
但是我对接下来的流程有些困惑,例如,假设我有一个数据库,其中包含一个包含ID,名称,密码和电子邮件的用户表,并且要登录某个应用程序,我需要输入电子邮件和密码。
按照上述步骤,我首先需要获取存储在数据库中的该用户的salt + hash密码。
题:
假设我正在使用一个简单的存储过程,那么唯一的方法就是像这样...
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
Run Code Online (Sandbox Code Playgroud)
然后执行第二步和第三步:
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);
}
Run Code Online (Sandbox Code Playgroud)
我担心的事实是,如果我使用从表中提取的数据来创建对象,这是否会使信息容易受到影响?
这是否还意味着使用此验证的唯一方法是仅基于用户名/电子邮件提取所有用户信息,只是在运行时检查输入密码和哈希值是否匹配,然后让该用户访问信息?
很抱歉,这听起来令人困惑,但是任何见解都会很棒。
看来您可能是在倒想。在传递给哈希函数之前,将盐添加到明文密码中。将最终结果存储在数据库中。
通常,盐是用户名。用户独有的,但用户之间有所不同的东西,可以抵抗字典攻击。
因此,对于用户名u,密码p,假设SHA2是哈希函数。将u + p连接起来得到一个盐值,然后对其进行哈希处理。
hashtext = SHA2(u + p) // in this case, + is concatenate
Run Code Online (Sandbox Code Playgroud)
hashtext是您存储在数据库中的内容。
对于登录,用户输入用户名u2和密码p2:
tryhash = SHA2(u2 + p2)
Run Code Online (Sandbox Code Playgroud)
在数据库中查询与u2匹配的用户记录,并带有tryhash的密码哈希文本
假设您有一个MVC动作,它接收loginViewModel,该动作由在页面中输入的明文电子邮件或用户名以及明文密码填充:
var loginUser = new User(loginViewModel);
CalcHash(loginUser);
var realUser = users.Find(loginUser.username);
if(realUser.HashPassword == loginUser.HashPassword)
// success
Run Code Online (Sandbox Code Playgroud)
虽然也可以将散列密码添加为数据访问方法的第二个参数,即。users.Find(username, hashPass),因此通常不会采用这种方式,因为即使密码失败,您也需要访问用户记录,以便增加密码失败次数并锁定帐户。