Bcrypt 验证密码

Bcrypt validate password

我正在尝试将散列密码存储在数据库中。这是我的代码:

 string passwords = textBox2.Text;
 string salt = BCrypt.Net.BCrypt.GenerateSalt(12);
 string hashPwd = BCrypt.Net.BCrypt.HashPassword(passwords, salt);
        try
        {
            SQLiteCommand command = new SQLiteCommand();
            connection.Open();
            command.Connection = connection;
            command.CommandText = ((@"INSERT INTO acc (UserName, Pass) VALUES ('" + textBox1.Text + "','" + hashPwd+ "');"));
            command.ExecuteNonQuery();
            connection.Close();
        }
        catch (Exception ex)
        {
            MessageBox.Show("Error:" + ex.ToString());
            return;
        }

Login/verification代码:

          try
          {   

            SQLiteDataAdapter sqlad = new SQLiteDataAdapter("SELECT  COUNT(*) From acc WHERE Username = '" + textBox1.Text + "' AND Pass = '" + textBox2.Text + "' ", connection);
            DataTable dt = new DataTable();
            sqlad.Fill(dt);`
            string userid = dt.Rows[0]["UserName"].ToString();
            string password = dt.Rows[0]["Pass"].ToString();
            bool flag = BCrypt.Net.BCrypt.Verify(textBox2.Text, password);

            if (userid == textBox1.Text && flag == true)
            {
                Form2 frm = new Form2();
                frm.Show();
            }
            else
            {
                MessageBox.Show("Invalid UserId or password");
            }
          }
          catch (Exception ex)
          {
            MessageBox.Show(ex.ToString());
            return;
          }  

我无法验证密码,出现错误,你能帮帮我吗?还有一个问题,我是否也应该在数据库中保存盐?

您的代码有几个问题:

1. SQL注射

您的插入代码块和验证代码块都容易受到 SQL 注入的攻击,因为它们允许您直接从用户输入中获取的文本进入执行的 SQL 字符串,他们可以利用该漏洞来破坏登录检查,或者破坏你的数据库。不要这样做!

2。您从数据库返回的 select 散列密码不 select 散列密码.. 或任何感兴趣的内容。

考虑一下你这里有什么:

SQLiteDataAdapter sqlad = new SQLiteDataAdapter(@"
    SELECT  
        COUNT(*) 
    From 
        acc 
    WHERE 
       Username = '" + textBox1.Text + "' 
       AND 
       Pass = '" + textBox2.Text + "' ", connection);

所以,假设我给了我的用户名 "Steve" 和密码 "hello",它被散列到 "ab123cdef",并插入到你的 acc table 为:

UserName    Pass
Steve       ab123cdef

当我用原始正确的用户和密码验证时,您的 select 语句显示 "give me the number of rows with username 'Steve' and pass 'hello'",这将 return 归零。

您的代码应在此处抛出异常:

string userid = dt.Rows[0]["UserName"].ToString();

因为结果集不包含用户名作为输出。

这是一个基本的小示例,使用您选择的库来展示如何成功插入和验证密码。

关于如何处理加盐,函数 HashPassword 已将加盐添加到密码散列中,因此如果您存储此输出,您就是在存储加盐。您在验证中使用的验证功能将为您处理和检查。

static void CreateUser(string username, string password)
{
    if (UserExists(username))
        throw new InvalidOperationException("User already exists");

    string salt = BCrypt.Net.BCrypt.GenerateSalt(12);
    // if you look at the hashed password, notice that it's prepended with the salt generated above
    string hashedPassword = BCrypt.Net.BCrypt.HashPassword(password, salt);

    using (SQLiteConnection connection = new SQLiteConnection(connectionString))
    {
        connection.Open();
        SQLiteCommand insertCommand = new SQLiteCommand(connection);
        insertCommand.CommandText = @"INSERT INTO acc (UserName, Pass) VALUES (@username, @hashedPass);";
        // use parameterised queries to mitigate sql injection
        insertCommand.Parameters.Add(new SQLiteParameter("@username", username));
        insertCommand.Parameters.Add(new SQLiteParameter("@hashedPass", hashedPassword));
        insertCommand.ExecuteNonQuery();
    }
}

要验证给定的 username/password,我们只需要从数据库返回哈希函数的输出来验证我们已经给出的内容。

static bool Verify(string username, string password)
{
    using (SQLiteConnection connection = new SQLiteConnection(connectionString))
    {
        connection.Open();

        SQLiteCommand checkUserCommand = new SQLiteCommand(connection)
        {
            CommandText = @"SELECT Pass FROM acc WHERE UserName = @username;"
        };

        checkUserCommand.Parameters.Add(new SQLiteParameter("@username", username));
        var hashedPassword = (string)checkUserCommand.ExecuteScalar();                
        return BCrypt.Net.BCrypt.Verify(password, hashedPassword);                
    }
}

用法类似于..

if (!UserExists(username))
{
    CreateUser(username, password);
    Console.WriteLine("User {0} created", username);
}
else
{
    bool loginOk = Verify(username, password);
    Console.WriteLine("Login ok?: {0}", loginOk);
}