如何防止此代码中的 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 中使用列而不是 *。并且请确保您没有将明文密码存储在数据库中