使用散列密码验证用户的流程?

时间:2015-08-28 04:41:46

标签: c# passwords

当我来到这一部分时,我正在阅读关于散列密码的article

验证密码

  1. 从数据库中检索用户的salt和hash。
  2. 将salt添加到给定的密码并使用相同的哈希值 哈希函数。
  3. 将给定密码的哈希值与来自的哈希值进行比较 数据库。如果匹配,则密码正确。否则,     密码不正确。
  4. 但我对此流程有点困惑,例如假设我有一个带有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);
        }
    

    我担心的是,如果我使用从表中提取的数据创建对象,是否会以某种方式使信息易受攻击?

    这也意味着使用此验证的唯一方法是仅根据用户名/电子邮件提取所有用户信息,以便在运行时检查输入密码和散列密码是否匹配,然后让所述用户访问该信息?

    如果这听起来令人困惑,我很抱歉,但任何见解都会很棒。

3 个答案:

答案 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. 根据用户名参数与用户名字段匹配查找用户的数据行 选择存储的盐场

  2. 将(1)中的salt附加到password参数并散列结果

  3. 根据username参数与username字段的匹配,查找用户的数据行 和(2)哈希密码字段的哈希结果。

  4. 如果找不到行,则密码哈希值不匹配且错误,因此请返回合适的错误代码

  5. 如果找到一行,则返回有用的用户数据,即名字,地址

  6. 如果存储过程处理了所有这些,那么Web服务器永远不需要知道salt是什么或哈希算法。哈希结果或盐从来没有传输出数据库服务器。

答案 2 :(得分:0)

我认为你理解正确,这是通常的工作流程:

  1. 按用户名SELECT password_hash FROM user WHERE email=?获取密码哈希。
  2. 从password_hash中提取salt,或从单独的字段中获取salt。
  3. 使用提取的盐计算输入密码的哈希值并比较哈希值。
  4. 验证密码无法在单个查询中完成,因为您首先必须提取salt。数据库系统通常不支持适当的散列函数,如 PBKDF2 BCrypt SCrypt ,因此您必须在代码中进行验证。除了盐之外,您还必须存储其他参数,例如成本因素和算法(以便面向未来),因此最好将所有这些参数存储在同一个数据库字段中。

    盐应该是一个至少20个字符的随机字符串,因此不安全将用户名用作salt,或者从其他信息中获取盐。