c# - 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!");
}
}
解决方案
但是,密码没有经过哈希处理。我找不到有关如何进行与数据库相关的散列的任何帮助。
您已经熟悉如何在此处将字符串存储到数据库中:
sqlCmd.Parameters.AddWithValue("@Password", txtPassword.Text);
由于您知道如何将密码作为 a 存储string
在数据库中,并且您还知道如何对密码进行哈希处理GetSHA1()
- 我们所要做的就是将哈希密码转换为string
.
GetSHA1
当前返回一个byte[]
哈希密码和用户名。
为了将byte[]
转换为 astring
我们应该将字节编码(将字节格式化为人类可读的文本)将其从字节编码为string
. 我们将使用System.Convert.ToBase64String()
接受 anybyte[]
并将其转换为字符串的方法。
一旦我们将散列字节编码为 astring
我们就不必再使用MatchSHA1
并且可以删除该方法。这是因为我们可以将string
s 与==
运算符或使用其他内置方法进行比较。
如果我们可以把哈希变成一个字符串而不是
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 或类似的东西。由于自己实现一个安全的盐和哈希函数可能会导致安全漏洞,我不建议自行实现它们。
推荐阅读
- unity3d - 如何减少统一的drawcall?
- xsl-fo - 页面方向取决于条件
- amazon-web-services - AWS Lambda 函数管道在部署阶段失败:操作执行失败角色...无效或无法假定
- heroku - 在 Heroku 评论应用程序中指定 Postgres 数据库计划
- javascript - 无名导入和导出如何在 JS 中工作
- sql - H2 - 创建具有两列的唯一索引
- c - C中的结构和动态内存分配?
- java - Hazelcast Java - Predicates.and 忽略除第一个以外的谓词
- java - Spring JsonDeserializer 不适用于 String 类型
- java - 无法在 Java 中运行多个 SQL 更新语句