首页 > 解决方案 > C# WPF 使用哈希和数据库登录和注册

问题描述

我想要达到的目标:

我想制作一个登录和注册的帐户系统。我已经有了登录和注册系统,这也是连接到数据库的。但是,密码没有经过哈希处理。我找不到有关如何进行与数据库相关的散列的任何帮助。另外,我还在想我怎么加一点盐,因为这样会更安全。

问题: 见上文

登录代码:

private void btn_login_Click(object sender, RoutedEventArgs e)
        {
            SqlConnection sqlCon = new SqlConnection("Server=xxxxx;Database=x;User Id=xxx;Password=xx;");
            try
            {
                if (sqlCon.State == System.Data.ConnectionState.Closed)
                    sqlCon.Open();
                String query = "SELECT COUNT(1) FROM tblUser WHERE Username=@Username AND Password=@Password";
                SqlCommand sqlCmd = new SqlCommand(query, sqlCon);
                sqlCmd.CommandType = System.Data.CommandType.Text;
                sqlCmd.Parameters.AddWithValue("@Username", txtUsername.Text);
                sqlCmd.Parameters.AddWithValue("@Password", txtPassword.Text);
                int count = Convert.ToInt32(sqlCmd.ExecuteScalar());
                if (count == 1)
                {
                    MessageBox.Show("Success!");
                }
                else
                {
                    MessageBox.Show("Wrong!");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally
            {
                sqlCon.Close();
            }
        }

我想实现的哈希东西

获取 SHA:

private static byte[] GetSHA1(string userID, string password)
    {
    SHA1CryptoServiceProvider sha = new SHA1CryptoServiceProvider();
    return sha.ComputeHash(System.Text.Encoding.ASCII.GetBytes(userID + password));
    }

匹配 SHA:

private static bool MatchSHA1(byte[] p1, byte[] p2)
    {
    bool result = false;
    if (p1 != null && p2 != null)
        {
        if (p1.Length == p2.Length)
            {
            result = true;
            for (int i = 0; i < p1.Length; i++)
                {
                if (p1[i] != p2[i])
                    {
                    result = false;
                    break;
                    }
                }
            }
        }
    return result;
    }

测试

private static void RunTest()
    {
    string userId = "OriginalGriff";
    string password = "NotMyPassword";
    string enteredPassword = "NotMyPassword";
    string notPassword = "notMyPassword";
    byte[] hashedPassword = GetSHA1(userId, password);
    if (MatchSHA1(hashedPassword, GetSHA1(userId, enteredPassword)))
        {
        Console.WriteLine("Log him in!");
        }
    else
        {
        Console.WriteLine("Don't log him in!");
        }
    if (MatchSHA1(hashedPassword, GetSHA1(userId, notPassword)))
        {
        Console.WriteLine("Will not happen!");
        }
    else
        {
        Console.WriteLine("Don't log him in!");
        }
    }

标签: c#wpfhashsha

解决方案


但是,密码没有经过哈希处理。我找不到有关如何进行与数据库相关的散列的任何帮助。

您已经熟悉如何在此处将字符串存储到数据库中:

sqlCmd.Parameters.AddWithValue("@Password", txtPassword.Text);

由于您知道如何将密码作为 a 存储string在数据库中,并且您还知道如何对密码进行哈希处理GetSHA1()- 我们所要做的就是将哈希密码转换为string.

GetSHA1当前返回一个byte[]哈希密码和用户名。

为了将byte[]转换为 astring我们应该将字节编码(将字节格式化为人类可读的文本)将其从字节编码为string. 我们将使用System.Convert.ToBase64String()接受 anybyte[]并将其转换为字符串的方法。

一旦我们将散列字节编码为 astring我们就不必再使用MatchSHA1并且可以删除该方法。这是因为我们可以将strings 与==运算符或使用其他内置方法进行比较

如果我们可以把哈希变成一个字符串而不是

if (MatchSHA1(hashedPassword, GetSHA1(userId, enteredPassword)))
{
    Console.WriteLine("Log him in!");
}

相反,我们可以使用更简单的

if (hashedPassword == SHA384(userId, enteredPassword))
{
    Console.WriteLine("Log him in!");
}

我们可以通过升级来进一步加强我们的哈希方式,SHA384因为它的高碰撞SHA1不再推荐使用。

我继续GetSHA1使用建议的更改在下面修改了您的方法

private static string GetSHA384(string userID, string password)
{
    // SHA classes are disposable, use using to ensure any managed resources are properly disposed of by the runtime
    using SHA384 sha = new SHA384CryptoServiceProvider();

    // convert the username and password into bytes
    byte[] preHash = Encoding.ASCII.GetBytes(userID + password);

    // hash the bytes
    byte[] hash = sha.ComputeHash(preHash);

    // convert the raw bytes into a string that we can save to a database
    return Convert.ToBase64String(hash);
}

为了存储密码只需替换

sqlCmd.Parameters.AddWithValue("@Password", txtPassword.Text);

与以下

sqlCmd.Parameters.AddWithValue("@Password", GetSHA384(txtUsername.Text, txtPassword.Text));

我还在想我怎么加一点盐

如果这是一个激情项目

SHA不包括盐渍的实现,为此您必须自己制作。我将把它作为练习留给读者或其他有帮助的开发人员。

如果这是一个生产项目

我建议使用现成的实现,例如 BCrypt 或类似的东西。由于自己实现一个安全的盐和哈希函数可能会导致安全漏洞,我不建议自行实现它们


推荐阅读