C# WPF 登录并注册哈希和数据库

C# WPF Login and Register with hashing and database

我想达到的效果:

我想做一个带登录和注册的账号系统。我已经有了登录和注册系统,这也连接到数据库。但是,密码未经过哈希处理。 我找不到任何关于如何进行与数据库相关的散列的帮助。 另外,我还在想怎么加点盐,这样比较安全

问题: 见上文

登录密码:

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

test:

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!");
        }
    }

However, the passwords are not hashed. I can't find any help on how to do the hashing in connection with the database.

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

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

既然您知道如何将密码作为 string 存储在数据库中,并且您还知道如何使用 GetSHA1() 散列密码 - 我们所要做的就是将散列密码进入 string.

GetSHA1 当前 returns 一个 byte[] 这是哈希密码和用户名。

为了将 byte[] 转换为 string,我们应该使用 Encode(format the bytes into human readable text) it from bytes into a string. We're going to use the System.Convert.ToBase64String() 方法将任何 byte[] 转换为字符串。

一旦我们将散列字节编码为 string,我们就不必再使用 MatchSHA1 并且可以删除该方法。这是因为我们可以将 strings 与 == 运算符或使用 other built-in methods.

进行比较

如果我们可以将散列变成字符串而不是

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

我们可以使用更简单的方法

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

我们可以通过升级到 SHA384 来进一步加强散列的方式,因为 SHA1no longer recommended for use because of it's high collision rate.

我继续按照建议的更改修改了您的 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));

I still wonder how I add a little salt

如果这是一个激情项目

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

如果这是一个生产项目

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