如何防止此代码中的 SQL 注入?
How to prevent SQL Injection in this code?
如何防止这些代码被 SQL 注入?这是我正在学习的登录系统。这是代码!
if (!(string.IsNullOrWhiteSpace(textBox1.Text)) && !(string.IsNullOrWhiteSpace(textBox2.Text)))
{
MySqlConnection mcon = new MySqlConnection("datasource = 127.0.0.1; port = 3306; username = root; password = ; database = rpgmaster;");
mcon.Open();
DataTable table = new DataTable();
MySqlDataAdapter adapter = new MySqlDataAdapter("Select * From users where Username = '" + textBox2.Text + "' and password = '" + textBox1.Text + "'", mcon);
adapter.Fill(table);
if (table.Rows.Count <= 0)
{
MessageBox.Show("Você não está registrado!");
}
else
{
MessageBox.Show("Logado com sucesso! ");
}
mcon.Close();
}
感谢您的帮助!真的很感谢!
使用参数
using (MySqlConnection mcon = new MySqlConnection(connectionString))
{
string commandText = "SELECT * FROM users WHERE Username = '@tbxText'"
SqlCommand command = new SqlCommand(commandText, mcon);
command.Parameters.AddWithValue("@tbxText", textBox2.Text);
}
尝试使用参数,请参阅下面更新的代码示例:
if (!(string.IsNullOrWhiteSpace(textBox1.Text)) && !(string.IsNullOrWhiteSpace(textBox2.Text)))
{
using (MySqlConnection mcon = new MySqlConnection("datasource = 127.0.0.1; port = 3306; username = root; password = ; database = rpgmaster;"))
{
mcon.Open();
MySqlCommand cmd = new MySqlCommand("Select * from users where username=?username and password=?password", mcon);
cmd.Parameters.Add(new MySqlParameter("username", textBox2.Text));
cmd.Parameters.Add(new MySqlParameter("password", textBox1.Text));
MySqlDataReader dr = cmd.ExecuteReader();
if (dr.HasRows == true)
{
MessageBox.Show("Você não está registrado!");
}
else
{
MessageBox.Show("Logado com sucesso! ");
}
}
}
如果您正在学习,您或许可以放弃这种旧的低级数据访问方式,转而使用更现代、更简单的方式。 Dapper 是一个图书馆的例子,它并没有超越你已经知道的东西,而是让你的生活更美好:
using(var conn = new MySqlConnection("conn str here"){
var sql = "SELECT count(*) FROM tblUsers WHERE username = @u AND password = @p";
var prm = new {
u = txtUsername.Text, //give your textboxes better names than textbox2,textbox1!
p = txtPassword.Text.GetHashCode() //do NOT store plain text passwords!
};
bool valid = await conn.QuerySingleAsync<int>(sql, prm) > 0;
if(valid)
... valid login code
else
... invalid login
}
对此的一些说明:
- dapper 是一种设备,您只需将 sql 和参数值提供给
- sql 包含@parameters 名称,如@u
- 匿名类型对象具有与参数名称同名的属性,具有一个值,如
u = "my username"
- 在运行ning查询时使用async/await; dapper 使这变得容易。避免在 运行
需要 10 秒的查询上干扰您的 UI
- 这种情况下只需要让db统计匹配的记录即可,不需要全部下载下来看有没有,所以我们使用
QuerySingleAsync<int>
查询单个类型的值,如果大于0,则登录有效
- 永远不要将密码以明文形式存储在数据库中。使用单向散列函数,如 MD5、SHA256 等,即使是低级别的 string.GetHashCode 也比存储明文好,特别是因为人们一直使用相同的密码,所以任何人都可以闯入您的数据库(非常容易;密码在代码) 将揭示人们可能在银行业务等中使用的密码。一方面,我们真的不能问如何防止像 SQL 注入这样的巨大安全漏洞,然后另一方面离开像明文密码这样的巨大安全漏洞;)
- 总是给你的文本框起一个比默认文本框X更好的名字——它需要几秒钟的时间并使你的代码易于理解。如果 Microsoft 将他们所有的 class 属性 名称都这样命名,那么整个框架将充满
myString.Int1
而不是 myString.Length
之类的东西,并且它将完全无法使用
- 人生苦短,不能花时间写
AddWithValue
陈述;使用 Dapper,Entity Framework,强类型数据集。一些数据库管理技术可以减轻编写代码的负担
Dapper 让您真正受益的地方在于它能够将对象转换为查询,反之亦然;上面这只是一个基本的计数示例,但假设您有一个用户 class:
class User
{
string Name { get; set; }
string HashedPassword { get; set; }
int age {get; set; }
}
并且您有一个相似的 table tblUsers
(列名与 属性 名称相同),那么您可以这样查询:
User u = new User() { Name = "someuser" };
User t = await conn.QuerySingleAsync<User>("SELECT Name, HashedPassword, Age FROM tblUsers WHERE Name = @Name", u);
我们想查找 someuser
用户的所有信息,所以我们用那个 Name
集创建一个新的 User
(我们也可以使用匿名类型,比如前面的示例),仅此而已,我们将其作为参数参数传递。 Dapper 将看到查询包含 @Name
,从我们传入的 u
用户中提取 Name
的内容,以及 运行 查询。当结果 return 时,它将为我们创建一个 User
实例,完全填充查询中的所有数据
要采用这种旧方法,我们必须:
- 有命令,
- 有联系,
- 添加参数和值,
- 打开连接,
- 运行 sql,
- 得到一个reader,
- 检查 reader 是否有行,
- 循环 reader 拉第一行,
- 制作一个新的
User
,
- 使用
reader.GetInt/GetString
等将列值一一拉出并
- 终于return新用户
- 哦,处理所有数据库的东西,关闭连接等
写那个代码重复,而且真的无聊。在计算中,当我们有一些重复和无聊的事情时,我们需要在一生中做数千次(比如序列化到 json、调用网络服务、设计 windows UI)我们找到一些方法让计算机做重复的无聊工作;他们比我们做得更快更准确。这正是 Dapper 所做的;它消除了无聊的重复并将其减少到一行,您可以在其中说出您想要返回的内容,使用什么查询,使用什么参数。它可以让您的 UI 正常工作:
await x.QueryAsync<type>(query, parameters)
赢了。寻找一些 Dapper 教程! (我没有隶属关系)
使用参数传递和检查它们的长度,在代码中使用存储过程而不是查询。在 Select
中使用列而不是 *
。并且请确保您没有将明文密码存储在数据库中
如何防止这些代码被 SQL 注入?这是我正在学习的登录系统。这是代码!
if (!(string.IsNullOrWhiteSpace(textBox1.Text)) && !(string.IsNullOrWhiteSpace(textBox2.Text)))
{
MySqlConnection mcon = new MySqlConnection("datasource = 127.0.0.1; port = 3306; username = root; password = ; database = rpgmaster;");
mcon.Open();
DataTable table = new DataTable();
MySqlDataAdapter adapter = new MySqlDataAdapter("Select * From users where Username = '" + textBox2.Text + "' and password = '" + textBox1.Text + "'", mcon);
adapter.Fill(table);
if (table.Rows.Count <= 0)
{
MessageBox.Show("Você não está registrado!");
}
else
{
MessageBox.Show("Logado com sucesso! ");
}
mcon.Close();
}
感谢您的帮助!真的很感谢!
使用参数
using (MySqlConnection mcon = new MySqlConnection(connectionString))
{
string commandText = "SELECT * FROM users WHERE Username = '@tbxText'"
SqlCommand command = new SqlCommand(commandText, mcon);
command.Parameters.AddWithValue("@tbxText", textBox2.Text);
}
尝试使用参数,请参阅下面更新的代码示例:
if (!(string.IsNullOrWhiteSpace(textBox1.Text)) && !(string.IsNullOrWhiteSpace(textBox2.Text)))
{
using (MySqlConnection mcon = new MySqlConnection("datasource = 127.0.0.1; port = 3306; username = root; password = ; database = rpgmaster;"))
{
mcon.Open();
MySqlCommand cmd = new MySqlCommand("Select * from users where username=?username and password=?password", mcon);
cmd.Parameters.Add(new MySqlParameter("username", textBox2.Text));
cmd.Parameters.Add(new MySqlParameter("password", textBox1.Text));
MySqlDataReader dr = cmd.ExecuteReader();
if (dr.HasRows == true)
{
MessageBox.Show("Você não está registrado!");
}
else
{
MessageBox.Show("Logado com sucesso! ");
}
}
}
如果您正在学习,您或许可以放弃这种旧的低级数据访问方式,转而使用更现代、更简单的方式。 Dapper 是一个图书馆的例子,它并没有超越你已经知道的东西,而是让你的生活更美好:
using(var conn = new MySqlConnection("conn str here"){
var sql = "SELECT count(*) FROM tblUsers WHERE username = @u AND password = @p";
var prm = new {
u = txtUsername.Text, //give your textboxes better names than textbox2,textbox1!
p = txtPassword.Text.GetHashCode() //do NOT store plain text passwords!
};
bool valid = await conn.QuerySingleAsync<int>(sql, prm) > 0;
if(valid)
... valid login code
else
... invalid login
}
对此的一些说明:
- dapper 是一种设备,您只需将 sql 和参数值提供给
- sql 包含@parameters 名称,如@u
- 匿名类型对象具有与参数名称同名的属性,具有一个值,如
u = "my username"
- 在运行ning查询时使用async/await; dapper 使这变得容易。避免在 运行 需要 10 秒的查询上干扰您的 UI
- 这种情况下只需要让db统计匹配的记录即可,不需要全部下载下来看有没有,所以我们使用
QuerySingleAsync<int>
查询单个类型的值,如果大于0,则登录有效 - 永远不要将密码以明文形式存储在数据库中。使用单向散列函数,如 MD5、SHA256 等,即使是低级别的 string.GetHashCode 也比存储明文好,特别是因为人们一直使用相同的密码,所以任何人都可以闯入您的数据库(非常容易;密码在代码) 将揭示人们可能在银行业务等中使用的密码。一方面,我们真的不能问如何防止像 SQL 注入这样的巨大安全漏洞,然后另一方面离开像明文密码这样的巨大安全漏洞;)
- 总是给你的文本框起一个比默认文本框X更好的名字——它需要几秒钟的时间并使你的代码易于理解。如果 Microsoft 将他们所有的 class 属性 名称都这样命名,那么整个框架将充满
myString.Int1
而不是myString.Length
之类的东西,并且它将完全无法使用 - 人生苦短,不能花时间写
AddWithValue
陈述;使用 Dapper,Entity Framework,强类型数据集。一些数据库管理技术可以减轻编写代码的负担
Dapper 让您真正受益的地方在于它能够将对象转换为查询,反之亦然;上面这只是一个基本的计数示例,但假设您有一个用户 class:
class User
{
string Name { get; set; }
string HashedPassword { get; set; }
int age {get; set; }
}
并且您有一个相似的 table tblUsers
(列名与 属性 名称相同),那么您可以这样查询:
User u = new User() { Name = "someuser" };
User t = await conn.QuerySingleAsync<User>("SELECT Name, HashedPassword, Age FROM tblUsers WHERE Name = @Name", u);
我们想查找 someuser
用户的所有信息,所以我们用那个 Name
集创建一个新的 User
(我们也可以使用匿名类型,比如前面的示例),仅此而已,我们将其作为参数参数传递。 Dapper 将看到查询包含 @Name
,从我们传入的 u
用户中提取 Name
的内容,以及 运行 查询。当结果 return 时,它将为我们创建一个 User
实例,完全填充查询中的所有数据
要采用这种旧方法,我们必须:
- 有命令,
- 有联系,
- 添加参数和值,
- 打开连接,
- 运行 sql,
- 得到一个reader,
- 检查 reader 是否有行,
- 循环 reader 拉第一行,
- 制作一个新的
User
, - 使用
reader.GetInt/GetString
等将列值一一拉出并 - 终于return新用户
- 哦,处理所有数据库的东西,关闭连接等
写那个代码重复,而且真的无聊。在计算中,当我们有一些重复和无聊的事情时,我们需要在一生中做数千次(比如序列化到 json、调用网络服务、设计 windows UI)我们找到一些方法让计算机做重复的无聊工作;他们比我们做得更快更准确。这正是 Dapper 所做的;它消除了无聊的重复并将其减少到一行,您可以在其中说出您想要返回的内容,使用什么查询,使用什么参数。它可以让您的 UI 正常工作:
await x.QueryAsync<type>(query, parameters)
赢了。寻找一些 Dapper 教程! (我没有隶属关系)
使用参数传递和检查它们的长度,在代码中使用存储过程而不是查询。在 Select
中使用列而不是 *
。并且请确保您没有将明文密码存储在数据库中