c# - 如何防止此代码中的 SQL 注入?
问题描述
如何防止这些代码注入 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();
}
谢谢您的帮助!真的很感激!
解决方案
如果您正在学习,您也许可以从这种旧的低级数据访问方式继续前进,并使用更现代和更简单的东西。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"
- 运行查询时使用 async/await;dapper 让这一切变得简单。避免在需要 10 秒才能运行的查询上卡住 UI
- 在这种情况下你只需要让db统计匹配的记录,你不需要全部下载来查找是否有,所以我们使用
QuerySingleAsync<int>
which查询单个类型的值,如果超过0,登录有效 - 永远不要将密码以明文形式存储在数据库中。使用单向哈希函数,如 MD5、SHA256 等,甚至是低级字符串。GetHashCode 比存储纯文本更好,特别是因为人们一直使用相同的密码,所以任何人都可以闯入您的数据库(非常容易;密码在代码中) 将揭示人们可能在银行等中使用的密码。一方面,我们不能真正问如何防止像 SQL 注入这样的巨大安全漏洞,另一方面又像明文一样留下巨大的安全漏洞密码;)
- 始终将您的文本框命名为比默认的 textboxX 更好的名称 - 这需要几秒钟并使您的代码易于理解。如果微软这样调用他们所有的类属性名称,那么整个框架将充满诸如
myString.Int1
而不是之类的东西myString.Length
,它将完全无法使用 - 生命太短暂,不能花时间写
AddWithValue
陈述;使用 Dapper、实体框架、强类型数据集.. 一些减轻编写代码负担的数据库管理技术
Dapper 为您带来真正好处的地方在于它能够将对象转换为查询,反之亦然;以上只是一个基本的计数示例,但假设您有一个 User 类:
class User
{
string Name { get; set; }
string HashedPassword { get; set; }
int age {get; set; }
}
你有一个tblUsers
相似的表(列名与属性名相同),然后你可以查询:
User u = new User() { Name = "someuser" };
User t = await conn.QuerySingleAsync<User>("SELECT Name, HashedPassword, Age FROM tblUsers WHERE Name = @Name", u);
我们想查找用户的所有信息,所以我们用那个集合someuser
创建一个新的(我们也可以使用匿名类型,就像前面的例子一样),没有别的,我们把它作为参数传递。Dapper 将看到查询 contains ,从我们传入的用户那里提取内容,然后运行查询。当结果返回时,它将为我们创建一个实例,完全填充来自查询的所有数据User
Name
@Name
Name
u
User
要做到这一点,我们必须:
- 有命令,
- 有联系,
- 添加参数和值,
- 打开连接,
- 运行sql,
- 找个读者,
- 检查阅读器是否有行,
- 循环拉动第一行的阅读器,
- 做一个新的
User
, - 使用
reader.GetInt/GetString
etc 将列值一一拉出, - 最后返回新用户
- 哦,处理所有数据库的东西,关闭连接等
编写该代码是重复的,而且真的很无聊。在计算中,当我们遇到重复和无聊的事情时,我们需要在一生中做数千次(比如序列化为 json、调用 web 服务、设计 windows UI),我们会找到一些方法让计算机做重复无聊的部分; 他们比我们做得更快、更准确。这正是 Dapper 所做的;它消除了无聊的重复性并将其简化为一行,您可以在其中说出您想要返回的内容,使用什么查询,使用什么参数。它使您的 UI 保持正常工作:
await x.QueryAsync<type>(query, parameters)
赢。寻找一些 Dapper 教程!(我没有隶属关系)