为什么我在使用 MD5 哈希的 C# 中遇到某种密码的连接问题?
Why I am having connection Issues with some kind of passwords in C# using MD5 hash?
根据我在数据库中存储的密码类型,我的程序在尝试在第一个 "if" 中执行 Reader.close() 时在 "Consulta" 方法上崩溃。
例如,如果我将密码设置为“1234”,我没有任何问题,而使用 "prueba" 则会发生崩溃,甚至不会进入 "catch"。
这是保存新用户的方法,在按钮事件中。
private void bbtnGuardar_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
DB con = new DB(path);
MD5 md5 = MD5.Create();
byte[] hash = md5.ComputeHash(Encoding.Default.GetBytes(tbPassword.Text));
String encryptedPassword = Encoding.Default.GetString(hash);
string query = "INSERT INTO IEM182_LOGIN (USUARIO, PASSWORD) VALUES " +
"('" + tbUsuario.Text + "', '" + encryptedPassword + "');";
try
{
con.Consulta(query);
MessageBox.Show("Nuevo usuario dado de alta correctamente");
limpiar_usuario();
}
catch
{
try
{
con.Cerrar();
query = "SELECT * FROM IEM182_LOGIN WHERE USUARIO = '" + tbUsuario.Text + "'";
con.Consulta(query);
if (con.Reader.Read())
{
MessageBox.Show("El nombre de usuario ya existe");
}
}
catch
{
MessageBox.Show("El usuario contiene caracteres no validos");
}
con.Cerrar();
}
这是包含一些方法的数据库class。
class DB
{
private SqlDataReader rdr;
private string path;
private SqlConnection con;
private SqlCommand cmd;
public DB(string cadenaConexion)
{
path = cadenaConexion;
con = new SqlConnection(path);
}
public void Consulta(string query)
{
if (Conexion.State == System.Data.ConnectionState.Open)
{
cmd = new SqlCommand(query, con);
Reader.Close();
Reader = cmd.ExecuteReader();
}
else
{
con.Open();
cmd = new SqlCommand(query, con);
Reader = cmd.ExecuteReader();
}
}
public SqlDataReader Reader
{
get { return rdr; }
set { rdr = value; }
}
public void Cerrar()
{
con.Close();
}
public SqlConnection Conexion
{
get { return con; }
set { con = value; }
}
这是你的问题:
byte[] hash = md5.ComputeHash(Encoding.Default.GetBytes(tbPassword.Text));
String encryptedPassword = Encoding.Default.GetString(hash);
绝对没有保证你从哈希算法得到的字节形成合法的unicode字符串,事实上我会说这是一个非常小的机会将产生可用的字符串。似乎您发现了一些奇怪的情况。这只是偶然。
您应该不通过Encoding.Default.GetString
管道传输这些字节,而您应该使用像 Base 64 编码这样的东西:
String encryptedPassword = Convert.ToBase64String(bytes);
这将生成一个没有古怪字符的字符串,这些字符不会在数据库往返中存活下来。
要取回哈希字节,您使用相同的 class:
进行解码
byte[] hash = Convert.FromBase64String(encryptedPassword);
现在,这是您的代码的唯一问题吗?
不,不是。
第二个问题,加上上面的问题,会给你的 SQL 执行带来麻烦:
string query = "INSERT INTO IEM182_LOGIN (USUARIO, PASSWORD) VALUES " +
"('" + tbUsuario.Text + "', '" + encryptedPassword + "');";
你应该永远不要通过字符串连接形成SQL,你应该使用参数。
由于您创建了一个方法,Consulta
执行此查询,实际上修改您的代码以使用参数是相当多的更改,但要执行上述 SQL、使用参数,你会做这样的事情:
string query = "INSERT INTO IEM182_LOGIN (USUARIO, PASSWORD) VALUES " +
"(@username, @password);";
var cmd = new SqlCommand();
cmd.CommandText = query;
cmd.Parameters.AddWithValue("@username", tbUsuario.Text);
cmd.Parameters.AddWithValue("@password", encryptedPassword);
cmd.ExecuteNonQuery();
具体如何更改 Consultas
方法来处理此问题取决于您,但 这是您必须采用的方式!
所以为了解决我遇到的问题,我使用了另一种加密方法
// byte array representation of that string
byte[] encodedPassword = new UTF8Encoding().GetBytes(password);
// need MD5 to calculate the hash
byte[] hash = ((HashAlgorithm)CryptoConfig.CreateFromName("MD5")).ComputeHash(encodedPassword);
// string representation (similar to UNIX format)
string encoded = BitConverter.ToString(hash)
// without dashes
.Replace("-", string.Empty)
// make lowercase
.ToLower();
并修复了第一个 "try/catch" 添加另一个 try/catch 以调用 con.Consulta() 方法并捕获无效字符。
根据我在数据库中存储的密码类型,我的程序在尝试在第一个 "if" 中执行 Reader.close() 时在 "Consulta" 方法上崩溃。
例如,如果我将密码设置为“1234”,我没有任何问题,而使用 "prueba" 则会发生崩溃,甚至不会进入 "catch"。
这是保存新用户的方法,在按钮事件中。
private void bbtnGuardar_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
DB con = new DB(path);
MD5 md5 = MD5.Create();
byte[] hash = md5.ComputeHash(Encoding.Default.GetBytes(tbPassword.Text));
String encryptedPassword = Encoding.Default.GetString(hash);
string query = "INSERT INTO IEM182_LOGIN (USUARIO, PASSWORD) VALUES " +
"('" + tbUsuario.Text + "', '" + encryptedPassword + "');";
try
{
con.Consulta(query);
MessageBox.Show("Nuevo usuario dado de alta correctamente");
limpiar_usuario();
}
catch
{
try
{
con.Cerrar();
query = "SELECT * FROM IEM182_LOGIN WHERE USUARIO = '" + tbUsuario.Text + "'";
con.Consulta(query);
if (con.Reader.Read())
{
MessageBox.Show("El nombre de usuario ya existe");
}
}
catch
{
MessageBox.Show("El usuario contiene caracteres no validos");
}
con.Cerrar();
}
这是包含一些方法的数据库class。
class DB
{
private SqlDataReader rdr;
private string path;
private SqlConnection con;
private SqlCommand cmd;
public DB(string cadenaConexion)
{
path = cadenaConexion;
con = new SqlConnection(path);
}
public void Consulta(string query)
{
if (Conexion.State == System.Data.ConnectionState.Open)
{
cmd = new SqlCommand(query, con);
Reader.Close();
Reader = cmd.ExecuteReader();
}
else
{
con.Open();
cmd = new SqlCommand(query, con);
Reader = cmd.ExecuteReader();
}
}
public SqlDataReader Reader
{
get { return rdr; }
set { rdr = value; }
}
public void Cerrar()
{
con.Close();
}
public SqlConnection Conexion
{
get { return con; }
set { con = value; }
}
这是你的问题:
byte[] hash = md5.ComputeHash(Encoding.Default.GetBytes(tbPassword.Text));
String encryptedPassword = Encoding.Default.GetString(hash);
绝对没有保证你从哈希算法得到的字节形成合法的unicode字符串,事实上我会说这是一个非常小的机会将产生可用的字符串。似乎您发现了一些奇怪的情况。这只是偶然。
您应该不通过Encoding.Default.GetString
管道传输这些字节,而您应该使用像 Base 64 编码这样的东西:
String encryptedPassword = Convert.ToBase64String(bytes);
这将生成一个没有古怪字符的字符串,这些字符不会在数据库往返中存活下来。
要取回哈希字节,您使用相同的 class:
进行解码byte[] hash = Convert.FromBase64String(encryptedPassword);
现在,这是您的代码的唯一问题吗?
不,不是。
第二个问题,加上上面的问题,会给你的 SQL 执行带来麻烦:
string query = "INSERT INTO IEM182_LOGIN (USUARIO, PASSWORD) VALUES " +
"('" + tbUsuario.Text + "', '" + encryptedPassword + "');";
你应该永远不要通过字符串连接形成SQL,你应该使用参数。
由于您创建了一个方法,Consulta
执行此查询,实际上修改您的代码以使用参数是相当多的更改,但要执行上述 SQL、使用参数,你会做这样的事情:
string query = "INSERT INTO IEM182_LOGIN (USUARIO, PASSWORD) VALUES " +
"(@username, @password);";
var cmd = new SqlCommand();
cmd.CommandText = query;
cmd.Parameters.AddWithValue("@username", tbUsuario.Text);
cmd.Parameters.AddWithValue("@password", encryptedPassword);
cmd.ExecuteNonQuery();
具体如何更改 Consultas
方法来处理此问题取决于您,但 这是您必须采用的方式!
所以为了解决我遇到的问题,我使用了另一种加密方法
// byte array representation of that string
byte[] encodedPassword = new UTF8Encoding().GetBytes(password);
// need MD5 to calculate the hash
byte[] hash = ((HashAlgorithm)CryptoConfig.CreateFromName("MD5")).ComputeHash(encodedPassword);
// string representation (similar to UNIX format)
string encoded = BitConverter.ToString(hash)
// without dashes
.Replace("-", string.Empty)
// make lowercase
.ToLower();
并修复了第一个 "try/catch" 添加另一个 try/catch 以调用 con.Consulta() 方法并捕获无效字符。