如何防止这段代码中的 SQL 注入?

Rav*_*ven 0 c# mysql forms windows sql-injection

如何防止这些代码被 SQL 注入?这是我正在学习的登录系统。这是代码!

\n
            if (!(string.IsNullOrWhiteSpace(textBox1.Text)) && !(string.IsNullOrWhiteSpace(textBox2.Text)))\n        {\n\n            MySqlConnection mcon = new MySqlConnection("datasource = 127.0.0.1; port = 3306; username = root; password = ; database = rpgmaster;");\n\n            mcon.Open();\n\n            DataTable table = new DataTable();\n\n            MySqlDataAdapter adapter = new MySqlDataAdapter("Select * From users where Username = '" + textBox2.Text + "' and password = '" + textBox1.Text + "'", mcon);\n           \n            adapter.Fill(table);\n\n            if (table.Rows.Count <= 0)\n            {\n                MessageBox.Show("Voc\xc3\xaa n\xc3\xa3o est\xc3\xa1 registrado!");\n            }\n            else\n            {\n                MessageBox.Show("Logado com sucesso! ");\n            }\n\n            mcon.Close();\n        }\n
Run Code Online (Sandbox Code Playgroud)\n

谢谢您的帮助!真的很感激!

\n

Cai*_*ard 5

如果您正在学习,您也许可以放弃这种旧的低级数据访问方式,并使用更现代、更简单的方式。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
}
Run Code Online (Sandbox Code Playgroud)

关于此的一些注释:

  • dapper 是一个设备,您只需向其提供 sql 和参数值即可
  • sql 保存@parameters 名称,例如@u
  • 匿名类型对象具有与参数名称同名的属性,其值如下u = "my username"
  • 运行查询时使用 async/await;dapper 让这一切变得简单。避免在需要 10 秒运行的查询上阻塞 UI
  • 在这种情况下,你只需要要求数据库统计匹配的记录,你不需要下载所有的记录来查找是否有,所以我们使用QuerySingleAsync<int>which来查询it类型的单个值,如果它超过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; }
}
Run Code Online (Sandbox Code Playgroud)

并且您有一个类似的表tblUsers(列名称与属性名称相同),那么您可以像这样查询:

User u = new User() { Name = "someuser" };
User t = await conn.QuerySingleAsync<User>("SELECT Name, HashedPassword, Age FROM tblUsers WHERE Name = @Name", u);
Run Code Online (Sandbox Code Playgroud)

我们想要查找someuser用户的所有信息,因此我们用UserName集合创建一个新的(我们也可以使用匿名类型,如前面的示例),而不做其他任何事情,然后将其作为参数传递。Dapper 将看到查询 contains ,从我们传入的用户中@Name提取 的内容,然后运行查询。当结果返回时,它将为我们创建一个实例,其中完全填充了查询中的所有数据NameuUser

要采用这种旧方法,我们必须:

  • 有一个命令,
  • 有联系,
  • 添加参数和值,
  • 打开连接,
  • 运行sql,
  • 找个读者,
  • 检查读者是否有行,
  • 循环读取器拉动第一行,
  • 制作一个新的User,
  • 使用reader.GetInt/GetStringetc将列值一一拉出,
  • 最后返回新用户
  • 哦,处理所有数据库的东西,关闭连接等

编写这些代码是重复的,而且非常无聊。在计算中,当我们遇到重复且无聊的事情时,我们需要在一生中执行数千次(例如序列化为 json、调用 Web 服务、设计 Windows UI),我们会找到一些方法让计算机执行重复的无聊操作; 他们比我们做得更快、更准确。这正是 Dapper 所做的;它消除了那种无聊的重复,并将其简化为一行,您可以在其中说出您想要返回的内容,使用什么查询,使用什么参数。它可以让你的 UI 正常工作:

await x.QueryAsync<type>(query, parameters)
Run Code Online (Sandbox Code Playgroud)

赢。寻找一些 Dapper 教程!(我没有任何隶属关系)