首页 > 解决方案 > 如何防止此代码中的 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();
        }

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

标签: c#mysqlwindowsformssql-injection

解决方案


如果您正在学习,您也许可以从这种旧的低级数据访问方式继续前进,并使用更现代和更简单的东西。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 ,从我们传入的用户那里提取内容,然后运行查询。当结果返回时,它将为我们创建一个实例,完全填充来自查询的所有数据UserName@NameNameuUser

要做到这一点,我们必须:

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

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

await x.QueryAsync<type>(query, parameters)

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


推荐阅读