修复我的代码以防止 sql 注入

Fixing my code to prevent sql injection

提问人:percival 提问时间:8/2/2022 更新时间:8/5/2022 访问量:293

问:

我在 DotNet Windows 窗体应用程序中进行了身份验证登录,我正在尽最大努力保护数据库免受 SQL 注入攻击,但我的代码中似乎存在错误的逻辑。任何帮助将不胜感激。

/* -UNSAFE command-
            sql = @"SELECT employee_no FROM public.tb_userlogin where
            username ='" + Convert.ToString(userText.Text) + "' AND password ='" + Convert.ToString(passText.Text) + "'";
            */

            conn.Open();
            sql = "SELECT employee_no FROM public.tb_userlogin where username = _username AND Decoypass = _password";

            EmpNo = code.Converter_string(sql).ToString();
            cmd = new NpgsqlCommand(sql, conn);
            cmd.Parameters.AddWithValue("_username", userText.Text);
            cmd.Parameters.AddWithValue("_password", passText.Text);

            if (userText.Text == String.Empty || passText.Text == String.Empty)
            {
                MessageBox.Show("Field cannot be empty!");
            }

            if (EmpNo != "0")//log in successfully
            {
                this.Hide();
                new ClientCrudFrm().Show();

            }
            else
            {
                MessageBox.Show("Please check your username or password", "Login Failed", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
                return;
            }
            if (conTable.Rows.Count == 1)
            {
                MessageBox.Show("login successfully");
            }
            else
            {
                MessageBox.Show("Error");
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show("Error: " + ex.Message,
                "Something went wrong", MessageBoxButtons.OK, MessageBoxIcon.Error);
            conn.Close();
        }

` 这是登录按钮内的完整代码:

 private void BtnLogin_Click(object sender, EventArgs e) //user login authentication
    {
        bool userValidated = validateUserInput(userText.Text);
        bool passValidated = validateUserInput(passText.Text);

        if (userValidated && passValidated)
        {
            getConnection();
        }
        
        try
        {
            NpgsqlConnection conn = new NpgsqlConnection("Host=localhost;Database=UserLogin;Username=postgres;Password=adminAdmin1");

            NpgsqlDataAdapter conDataAdapter = new NpgsqlDataAdapter();
            //NpgsqlDataAdapter conDataAdapter = new NpgsqlDataAdapter("select * from public.tb_userlogin where username='" + userText.Text + "'and password='" + passText.Text + "'", conn);
            DataTable conTable = new DataTable();
            conDataAdapter.Fill(conTable);

            /* -UNSAFE command-
            sql = @"SELECT employee_no FROM public.tb_userlogin where
            username ='" + Convert.ToString(userText.Text) + "' AND password ='" + Convert.ToString(passText.Text) + "'";
            */

            string username = userText.Text;
            string password = passText.Text;

            conn.Open();
            conDataAdapter.SelectCommand = cmd;
            cmd = new NpgsqlCommand(sql, conn);
            cmd = new NpgsqlCommand("SELECT * FROM public.tb_userlogin where username = $username AND password = $password", conn);

            EmpNo = code.Converter_string(sql).ToString();
            

            cmd.Parameters.AddWithValue("$username", userText.Text);
            cmd.Parameters.AddWithValue("$username", passText.Text);
            NpgsqlDataReader dr = cmd.ExecuteReader();

            if (userText.Text == String.Empty || passText.Text == String.Empty)
            {
                MessageBox.Show("Field cannot be empty!");
            }

            if (EmpNo != "0")//log in successfully
            {
                this.Hide();
                new ClientCrudFrm().Show();

            }
            else
            {
                MessageBox.Show("Please check your username or password", "Login Failed", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
                return;
            }
            if (conTable.Rows.Count == 1)
            {
                MessageBox.Show("login successfully");
            }
            else
            {
                MessageBox.Show("Error");
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show("Error: " + ex.Message,
                "Something went wrong", MessageBoxButtons.OK, MessageBoxIcon.Error);
            conn.Close();
        }
    }

使用上面更新的代码,当我登录时,这里说一个新错误:

"The SelectCommand property has not been initialized before calling Fill"
PostgreSQL 数据库设计 Windows C# SQL 注入

评论

0赞 jjanes 8/2/2022
占位符以 $ 或 @ 开头,而不是以 _ 开头。
0赞 percival 8/2/2022
谢谢,我尝试了前缀 $ 和 :它说语法错误在接近“$”。虽然前缀@,但错误表示运算符不存在:@ 字符变化。无论如何,我正在使用 Postgresql 数据库。
0赞 Shay Rojansky 8/3/2022
你能更新你的代码以使用@前缀吗?这应该有效。应将其添加到 SQL CommandText 中,但不需要在 AddWithValue 中执行此操作。或者使用位置占位符(1 美元、2 美元),如下所述。
1赞 Joel Coehoorn 8/5/2022
注射并不是唯一的问题。将裸密码存储在列中是非常不行的。

答:

0赞 Phill W. 8/2/2022 #1

来自:Npgsql 文档,使用 、 等作为参数的占位符,如下所示:$1$2

sql = "SELECT employee_no"
    + "FROM public.tb_userlogin"
    + "where username = $1"
    + "AND Decoypass = $2"
    ;

评论

0赞 percival 8/2/2022
相当解决,但是当我在这里登录时说:08P01绑定消息提供0个参数,但是准备好的语句“”需要2个
0赞 Shay Rojansky 8/3/2022
如果您使用位置参数($1、$2),则在添加参数时不要在参数上定义名称。如果这不起作用,请发布完整的代码。
0赞 percival 8/3/2022
我将向您展示登录按钮内的代码,我进行了一些更改。