2016-06-19 240 views
0

我試圖在數據庫中存儲哈希密碼。這裏是我的代碼:Bcrypt驗證密碼

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; 
     } 

登錄/驗證碼

  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; 
      } 

我無法驗證密碼,我得到的錯誤,你能幫助我嗎?還有一個問題,我應該在數據庫中儲存鹽嗎?

+2

爲什麼在你的SELECT語句,你有'並通過= ' 「+ textBox2.Text +」''?數據庫中的密碼是散列的,大概'textBox2.Text'包含純文本,所以這找不到任何東西。您還要返回計數,而不是「用戶名」和「通過」列,因此這些將不在結果集中。最後,可能想要閱讀SQL注入。 – steve16351

+0

如何將用戶輸入的密碼與數據庫中的哈希值進行比較? –

+0

@LuisVito看看[這篇文章](https://crackstation.net/hashing-security.htm),尤其是[本節](https://crackstation.net/hashing-security.htm#properhashing) 。相關步驟在此處列出。請考慮閱讀完整的文章;這是一個很好的:-) – khlr

回答

2

有幾個與你的代碼的問題:

1 SQL注入

無論您的插入和驗證碼塊容易受到SQL注入,因爲它們允許你的文本從用戶直接拿輸入到執行的SQL字符串中,它們可以用來破壞登錄檢查或破壞數據庫的漏洞。不要這樣做!

2.您從數據庫中選擇的散列密碼不會選擇哈希密碼..或任何感興趣的東西。

想想你有什麼在這裏:

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

所以,讓我們說我給我的用戶名是「史蒂夫」,密碼爲「你好」,這得到了散列以「ab123cdef」,並插入到你的acc表:

UserName Pass 
Steve  ab123cdef 

當我帶着原來正確的用戶名和密碼來驗證這一點,你的SELECT語句說:「給我行的數量與用戶名‘史蒂夫’,並通過‘你好’」,這將適時歸零。

您的代碼應該在這裏拋出異常:

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

由於結果集不包含用戶名作爲輸出。

這是一個基本的小例子,它使用您選擇的庫來展示如何成功插入和驗證密碼。

關於如何處理鹽,函數HashPassword已將salt加入密碼哈希中,因此如果存儲此輸出,則存儲salt。您在驗證中使用的驗證功能將處理併爲您檢查。

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(); 
    } 
} 

要驗證一個給定的用戶名/密碼,我們需要從數據庫返回的是哈希函數來驗證對我們已經給出什麼樣的輸出。

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); 
} 
+0

非常感謝。我會閱讀有關注射。 –