2012-06-02 108 views
0

我在使用來自登錄頁面的普通數據庫驗證來自數據庫的散列密碼方面遇到了很大的麻煩。 如何通過比較這兩passwords.Here來驗證用戶是我的註冊頁面代碼:如何比較散列密碼與普通密碼?

protected void Button1_Click(object sender, EventArgs e) 
{ 

    SHA384CryptoServiceProvider sh = new SHA384CryptoServiceProvider(); 
    byte[] plainbytes = Encoding.ASCII.GetBytes(TextBox2.Text); 
    var sha = sh.ComputeHash(plainbytes); 
    byte[] hashbytes = sh.Hash; 
    SqlConnection con = new SqlConnection(constr); 
    SqlCommand cmd = new SqlCommand("RegisterUser",con); 
    cmd.CommandType = CommandType.StoredProcedure; 
    SqlParameter param = null; 
    param = cmd.Parameters.Add("@username",SqlDbType.VarChar,10); 
    param.Value = TextBox1.Text; 
    param = cmd.Parameters.Add("@password", SqlDbType.VarChar, 20); 
    param.Value = BitConverter.ToString(hashbytes); 
    try 
    { 
     con.Open(); 
     cmd.ExecuteNonQuery(); 
     Label4.Text = "Successfully added account!!!"; 
    } 
    catch (Exception ex) 
    { 
     throw new Exception("Exception adding account"+ex.Message); 
    } 
    finally 
     { 
      con.Close(); 
     } 
} 

如何比較這密碼用一個從登錄頁面來...幫助我走出傢伙...

代碼鹽HASH: -

private static string CreateSalt(int size) 

{ 

    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); 

    byte[] buff = new byte[size]; 

    rng.GetBytes(buff); 

    return Convert.ToBase64String(buff); 

} 

private static string CreatePasswordHash(string pwd, string salt) 

{ 

    string saltAndPwd = String.Concat(pwd, salt); 

    string hashedPwd = 

    FormsAuthentication.HashPasswordForStoringInConfigFile(saltAndPwd, "SHA1"); 

    hashedPwd = String.Concat(hashedPwd, salt); 

    return hashedPwd; 

} 

protected void btnregister_Click(object sender, EventArgs e) 

{ 

    int saltSize = 5; 

    string salt = CreateSalt(saltSize); 

    string passwordHash = CreatePasswordHash(txtPassword.Text, salt); 

    try 

    { 

     StoreAccountDetails(txtUserName.Text, passwordHash); 

    } 

    catch (Exception ex) 

    { 

     lblMessage.Text = ex.Message; 

    } 

} 

private void StoreAccountDetails(string userName,string passwordHash) 

{ 

    SqlConnection conn = new SqlConnection(constr); 

    SqlCommand cmd = new SqlCommand("INSERT INTO Users VALUES(@userName, @passwordHash)", conn); 

    SqlParameter sqlParam = null; 

    sqlParam = cmd.Parameters.Add("@userName", SqlDbType.VarChar,20); 

    sqlParam.Value = userName; 

    sqlParam = cmd.Parameters.Add("@passwordHash ", SqlDbType.VarChar,50); 

    sqlParam.Value = passwordHash; 

    try 

    { 

     conn.Open(); 

     cmd.ExecuteNonQuery(); 

     lblMessage.Text = "User Added Successfully!!!"; 

    } 

    catch(Exception ex) 

    { 

    throw new Exception("Exception adding account. " + ex.Message); 

    } 

    finally 

    { 

     conn.Close(); 

    } 

} 

private bool VerifyPassword(string suppliedUserName,string suppliedPassword) 

{ 

    bool passwordMatch=false; 

    SqlConnection conn = new SqlConnection(constr); 

    SqlCommand cmd = new SqlCommand("SELECT PasswordHash FROM Users WHERE UserName = @userName", conn); 

    SqlParameter sqlParam = cmd.Parameters.Add("@userName",SqlDbType.VarChar,20); 

    sqlParam.Value = suppliedUserName; 

    try 

    { 

     conn.Open(); 

     SqlDataReader reader = cmd.ExecuteReader(); 

     reader.Read(); 

     string dbPasswordHash = reader.GetString(0); 

     int saltSize = 5; 

     string salt = CreateSalt(saltSize); 

     reader.Close(); 

     string hashedPasswordAndSalt =CreatePasswordHash(suppliedPassword, salt); 

     passwordMatch = hashedPasswordAndSalt.Equals(dbPasswordHash); 

    } 

    catch (Exception ex) 

    { 

     throw new Exception("Execption verifying password. " +ex.Message); 

    } 

    finally 

    { 

     conn.Close(); 

    } 

    return passwordMatch; 
} 


protected void btnlogon_Click(object sender, EventArgs e) 

{ 

    bool passwordVerified=false; 

    try 

    { 

     passwordVerified =VerifyPassword(txtUserName.Text, txtPassword.Text); 

    } 

    catch (Exception ex) 

    { 

     lblMessage.Text = ex.Message; 

     return; 

    } 

    if (passwordVerified == true) 

    { 



     lblMessage.Text = "Logon successful: User is authenticated"; 

    } 

    else 

    { 

     lblMessage.Text = "Invalid username or password"; 

    } 

} 
+0

實際上比較在哪裏? – Regfor

+0

我更新了比較logig ...你可以幫我糾正d代碼... thnx提前... – biki

+0

你可以發佈你正在使用的實際代碼?這仍然不正確。我可以告訴你,因爲你在searchtable()中使用了hashbyte並且該變量不存在。 –

回答

2

立即更新

你更新你的代碼,我仍然看到了一些問題。你應該使用Salt,但首先你需要你的代碼來實際工作。添加鹽很容易。

「mypassword」的一個簡單SHA哈希產生比20個字符大得多的字符串。您無法在20個字符的字段中填入base64的散列密碼。更改列大小和代碼以支持更大的哈希。

更新2

這裏是與鹽散列代碼。你必須更新你的RegisterUser存儲過程以存儲salt以及用戶名和散列密碼。您需要爲每個用戶添加一個新的Salt。鹽本身不需要被散列或加密。

您還需要從LogInUser存儲過程中返回salt。下面

閱讀評論:

private byte[] Combine(byte[] a, byte[] b) 
{ 
    byte[] c = new byte[a.Length + b.Length]; 
    System.Buffer.BlockCopy(a, 0, c, 0, a.Length); 
    System.Buffer.BlockCopy(b, 0, c, a.Length, b.Length); 
    return c; 
} 

protected void Button1_Click(object sender, EventArgs e) 
{  
    byte[] salt = new byte[16]; 
    RNGCryptoServiceProvider random = new RNGCryptoServiceProvider(); 
    random.GetNonZeroBytes(salt); 

    SHA384CryptoServiceProvider sh = new SHA384CryptoServiceProvider(); 
    byte[] plainbytes = Encoding.ASCII.GetBytes(TextBox2.Text); 

    var saltedBytes = Combine (salt, plainbytes); 
    var sha = sh.ComputeHash(saltedBytes); 

    SqlConnection con = new SqlConnection(constr); 
    SqlCommand cmd = new SqlCommand("RegisterUser",con); 
    cmd.CommandType = CommandType.StoredProcedure; 

    SqlParameter param = null; 
    param = cmd.Parameters.Add("@username",SqlDbType.VarChar,10); 
    param.Value = TextBox1.Text; 

    param = cmd.Parameters.Add("@password", SqlDbType.VarChar, 128); 
    param.Value = Convert.ToBase64String(sha); 

    // Store salt to use when comparing. 
    param = cmd.Parameters.Add("@salt", SqlDbType.VarChar, 128); 
    param.Value = Convert.ToBase64String(salt); 

    try 
    { 
     con.Open(); 
     cmd.ExecuteNonQuery(); 
     Label4.Text = "Successfully added account!!!"; 
    } 
    catch (Exception ex) 
    { 
     throw new Exception("Exception adding account"+ex.Message); 
    } 
    finally 
    { 
     con.Close(); 
    } 
} 

public bool searchtable() 
{   
    SqlConnection con = new SqlConnection(constr); 
    SqlCommand cmd = new SqlCommand("LogInUser",con); 
    cmd.CommandType = CommandType.StoredProcedure; 

    SqlParameter param = null; 
    param = cmd.Parameters.Add("@username",SqlDbType.VarChar,10); 
    param.Value = TextBox1.Text; 

    try 
    { 
     con.Open(); 
     SqlDataReader reader = cmd.ExecuteReader(); 
     reader.Read(); 

     // Get the salt hashed password 
     string dbpassmatch = reader.GetString(0); 

     // Get the salt 
     byte[] salt = Convert.FromBase64String(reader.GetString(1)); 

     // Recreate the salted hashed password 
     byte[] plainbyte = Encoding.ASCII.GetBytes(TextBox2.Text); 
     SHA384CryptoServiceProvider sh = new SHA384CryptoServiceProvider(); 
     var saltedBytes = Combine (salt, plainbytes); 
     var sha = sh.ComputeHash(saltedBytes);    

     // Now it matches what you did in insert. 
     String dbpassword = Convert.ToBase64String(sha); 

     reader.Close(); 

     return dbpassword.Equals(dbpassmatch); 
    } 
    catch (Exception ex) 
    { 
     throw new Exception("Exception adding account" + ex.Message); 
    } 
    finally 
    { 
     con.Close(); 
    } 
} 
+0

你的鹽在哪裏? – ThiefMaster

+0

@ThiefMaster在我的廚房櫃檯上。 –

+0

@AndrewFinnell:謝謝哥們......它解決了...... – biki

4

簡單。您散列來自登錄頁面的密碼,並將散列代碼與數據庫中的散列代碼進行比較。


由於文本應該處理相同的兩次,使該部分單一功能。將文本轉換爲字節時,使用UTF-8,ASCII編碼不處理所有字符:

public static string HashString(string value) { 
    SHA384CryptoServiceProvider sh = new SHA384CryptoServiceProvider(); 
    byte[] plainbytes = Encoding.UTF8.GetBytes(value); 
    byte[] hash = sh.ComputeHash(plainbytes); 
    return BitConverter.ToString(hashbytes); 
} 
+0

嘿你可以告訴最新的錯誤在登錄頁面...我真的陷入了它......幫助我...... – biki

+0

@biki:你已經將散列作爲base64存儲在數據庫中,因此您必須對登錄頁面的密碼進行同樣的操作。 – Guffa

+0

其實我也試過,但結果是一樣的...現在該怎麼做... – biki

0

你可以做散列在數據庫端,而不是應用端。這將是最簡單的,你將密碼作爲純文本發送到寄存器存儲過程,它將散列它(像sha1) 然後你將再次發送密碼,當用戶執行登錄時,存儲過程將尋找您發送的用戶名,然後將散列密碼並將其與註冊期間保存的密碼進行比較。

+0

和我應該怎麼做...任何想法? – biki

+0

這應該做的加密技巧:hashbytes('sha1','密碼') 那是註冊。那麼你可以做一個選擇,如下所示:select * from user其中userName = _userName和password = hashbytes('sha1',_ password) –

+0

用於sql server,如果你使用MySql,那麼:SHA1('password' ); –

2

你的代碼是從安全角度來看,非常糟糕:

  1. 使用的鹽。通常在db中散列旁邊存儲一個隨機值(64位或更多)。
  2. 使用一個緩慢的KDF,如PBKDF2,bcrypt或scrypt
    PBKDF2是最容易的,因爲.NET已經包含了一個實現:Rfc2898DeriveBytes Class
  3. 不要使用,但Encoding.UTF8。包含非ASCII字符的其他密碼變得非常弱。

然後要驗證輸入的密碼,從數據庫讀取哈希和鹽。使用從db中讀取的鹽散列候選密碼,並比較散列。


ASP.net還包含一個名爲Membership的庫,但我不太熟悉它。

+0

@codeln:thnx的信息...我用鹽修改了我的代碼......代碼中出現了什麼錯誤? – biki

+1

@biki'FormsAuthentication.HashPasswordForStoringInConfigFile'糟透了。不要使用它。 'Rfc2898DeriveBytes'好得多。 – CodesInChaos