C# 防止SQL注入
我试图阻止sql注入:比如1=1,等等。第一次这样做,我不确定我是否做对了 下面是代码:连接字符串就在那里。为了回答这个问题,我刚刚删除了它C# 防止SQL注入,c#,sql,ado.net,sql-injection,C#,Sql,Ado.net,Sql Injection,我试图阻止sql注入:比如1=1,等等。第一次这样做,我不确定我是否做对了 下面是代码:连接字符串就在那里。为了回答这个问题,我刚刚删除了它 public void btnSubmit_Click(object sender, EventArgs e) { String login = txtUser.Text; String pass = txtPass.Text; string connString = "";
public void btnSubmit_Click(object sender, EventArgs e)
{
String login = txtUser.Text;
String pass = txtPass.Text;
string connString = "";
SqlConnection conn = new SqlConnection(connString);
conn.Open();
SqlCommand cmd = new SqlCommand("Select Users,Pass from logintable where Users='" + txtUser.Text + "' and Pass='" + txtPass.Text + "'", conn);
cmd.Parameters.Add("@Users", SqlDbType.VarChar, 20).Value = login;
SqlDataReader dr=cmd.ExecuteReader();
if(dr.Read())
{
new Login().Show();
}
else
{
lblFail.Text="Invalid username or password";
}
}
请注意您在以下内容中使用的字符串连接:
"Select Users,Pass from logintable where Users='" + txtUser.Text + "' and Pass='" + txtPass.Text + "'"
这就是代码容易被注入的原因。您需要参数占位符:
"Select Users, Pass from logintable where Users=@Users and Pass=@Pass", conn);
您可以找到如何正确使用参数的完整示例。不,这是完全错误的。您仍然可以通过
txtser.Text
和txtPass.Text
进行注入,因为您使用的是字符串连接
您需要在查询中使用这两个值的参数,然后在执行之前将这两个.Text
属性绑定到查询上
SqlCommand cmd = new SqlCommand("Select Users,Pass from logintable where Users=@username and Pass=@password", conn);
cmd.Parameters.AddWithValue("@username", txtUser.Text);
cmd.Parameters.AddWithValue("@password", txtPass.Text);
当然,您不应该像这样直接以明文形式存储密码。您应该查看直接向查询传递值的情况。它导致Sql注入。因此,您需要使用Sql参数来避免它。给你一个主意
SqlCommand cmd = new SqlCommand("Select Users,Pass from logintable where Users=@user and Pass=@password", conn);
cmd.Parameters.AddWithValue("@user", txtUserName.Text);
cmd.Parameters.AddWithValue("@password", txtPassword.Text);
reader = cmd.ExecuteReader();
您使用的是
命令
对象,但您没有参数化不符合其用途的值,您可以在命令对象上使用AddWithValue()
方法来定义其参数
string query = "Select Users,Pass from logintable where Users=@user and Pass=@pass";
SqlCommand cmd = new SqlCommand(query, conn);
cmd.Parameters.AddWithValue("@user", txtUser.Text);
cmd.Parameters.AddWithValue("@pass", txtPass.Text);
此外,您可以从命令
对象中使用ExecuteScalar()
,而不是使用DataReader
对象获取结果中的单个值
请尝试以下代码段:
string connStr = "connection string here";
string sqlStatement = @"SELECT COUNT(*) TotalCount
FROM logintable
WHERE Users=@user and Pass=@pass";
using (SqlConnection conn = new SqlConnection(connStr))
{
using(SqlCommand comm = new SqlCommand())
{
comm.Connection = conn;
comm.CommandText = sqlStatement;
comm.CommandType = CommandType.Text;
comm.Parameters.AddWithValue("@user", txtUser.Text);
comm.Parameters.AddWithValue("@pass", txtPass.Text);
try
{
conn.Open();
int _result = Convert.ToInt32(comm.ExecuteScalar());
if (_result > 0)
{
new Login().Show();
}
}
catch(SqlException e)
{
// do something with the exception
// do not hide it
// e.Message.ToString()
}
}
}
为了正确编码
- 使用
使用
语句处理propr对象
- 使用
块正确处理对象try catch
SqlCommand cmd = new SqlCommand("Select Users, Pass from logintable where Users= @Users AND Pass=@Pass", conn);
cmd.Parameters.Add("@Users", SqlDbType.VarChar, 20);
cmd.Parameters.Add("@Pass", SqlDbType.VarChar, 20);
cmd.Parameters["@Users"].Value = login;
cmd.Parameters["@Pass"].Value = pass;
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
{
new Login().show();
}
else
{
lblFail.Text = "Invalid username and password";
}
reader.Close();
reader.Dispose();
conn.Close();
conn.Dispose();
希望这有帮助。您应该在try-catch块中使用上述代码,在finally块中使用Close/Dispose调用。旁注:以明文存储密码是不好的。您应该使用强KDF正确地散列它们。查看关于什么是必需的详细信息,并深入了解为什么我们需要使用KDFs而不是普通哈希。