问题描述
我想要达到的目标:
我想制作一个登录和注册的帐户系统。我已经有了登录和注册系统,这个也是连接数据库的。但是,密码没有经过哈希处理。 我找不到有关如何进行与数据库相关的散列的任何帮助。 另外,我还在想怎么加一点盐,这样比较安全。
问题: 见上
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,notPassword)))
{
Console.WriteLine("Will not happen!");
}
else
{
Console.WriteLine("Don't log him in!");
}
}
解决方法
但是,密码没有经过哈希处理。我找不到有关如何对数据库进行哈希处理的任何帮助。
您已经熟悉如何在此处将字符串存储到数据库中:
sqlCmd.Parameters.AddWithValue("@Password",txtPassword.Text);
既然您知道如何将密码作为 string
存储在数据库中,并且您还知道如何使用 GetSHA1()
散列密码 - 我们要做的就是将散列的密码变成一个string
。
GetSHA1
当前返回一个 byte[]
,它是经过哈希处理的密码和用户名。
为了将 byte[]
变成 string
,我们应该Encode(将字节格式化为人类可读的文本)将它从字节变成 {{ 1}}。我们将使用 System.Convert.ToBase64String()
方法接受任何 string
并将其转换为字符串。
一旦我们将散列字节编码为 byte[]
,我们就不必再使用 string
并且可以删除该方法。这是因为我们可以将 MatchSHA1
与 string
运算符或使用 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
是 no longer recommended for use because of it's high collision rate.
我继续使用推荐的更改修改了下面的 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));
不包括加盐的实现,为此您必须自己制作。我将把它作为练习留给读者或其他有帮助的开发者。
如果这是一个生产项目
我建议使用现成的实现,如 BCrypt 或类似的东西。由于自己实现安全的盐和哈希函数可能会导致安全漏洞我不建议自己实现它们。