1

我在使用来自登录页面的普通密码验证数据库中的哈希密码时遇到了很大的麻烦。如何通过比较这两个密码来验证用户。这是我的注册页面代码:

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

如何将此密码与来自登录页面的密码进行比较...帮帮我...

带有 SALT 的 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";

    }

}
4

4 回答 4

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);
}
于 2012-06-02T13:59:10.973 回答
2

从安全的角度来看,您的代码非常糟糕:

  1. 使用盐。通常一个随机值(64 位或更多)与 db 中的哈希一起存储。
  2. 使用慢速 KDF,例如 PBKDF2、bcrypt 或 scrypt
    PBKDF2 是最简单的,因为 .net 已经包含一个实现:Rfc2898DeriveBytes 类
  3. 不要使用Encoding.ASCII,但是Encoding.UTF8。其他包含非 ASCII 字符的密码会变得非常弱。

然后要验证输入的密码,从数据库中读取哈希和盐。用您从数据库中读取的盐对候选密码进行哈希处理,并比较哈希值。


ASP.net 还包含一个名为 的库Membership,但我对它不太熟悉。

于 2012-06-02T14:49:23.663 回答
2

更新

现在您更新了代码,我仍然看到一些问题。您应该使用 Salt,但首先您需要您的代码实际工作。添加盐很容易。

“mypassword”的简单 SHA 哈希会产生一个远大于 20 个字符的字符串。您无法将 base64 的哈希密码放入 20 个字符的字段中。更改列大小和您的代码以支持更大的散列。

更新 2

这是哈希上带有 Salt 的代码。您必须更新 RegisterUser 存储过程以存储盐以及用户名和哈希密码。每个用户都需要一个新的 Salt。盐本身不需要散列或加密。

您还需要从 LogInUser 存储过程中返回盐。

阅读以下评论:

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();
    }
}
于 2012-06-02T14:47:12.437 回答
0

您可以在数据库端进行散列,而不是应用程序端。这将是最简单的,您将密码作为纯文本发送到注册存储过程,它将对其进行哈希处理(使用 sha1 之类的东西)然后您将在用户执行登录时再次发送密码,存储过程将查找您发送的用户名,然后将散列密码并将其与注册期间保存的密码进行比较。

于 2012-06-02T14:00:38.357 回答