【问题标题】:How do I pass multiple parameters to a sqlite IN clause and protect against SQL injection?如何将多个参数传递给 sqlite IN 子句并防止 SQL 注入?
【发布时间】:2020-01-19 23:47:27
【问题描述】:

我在 UWP 项目中使用The Microsoft.Data.Sqlite library 相关的 sqlite API。

我发现如果我在参数化 SQL 语句中使用IN 条件,它不会返回正确的结果。

例如,如果 SQL 语句如下所示:

sqliteCommand.CommandText = @"delete from [test_table] where col1 in(@para1,@para2)";
sqliteCommand.Parameters.Add(new SqliteParameter("@para1", '1'));
sqliteCommand.Parameters.Add(new SqliteParameter("@para2", '2'));
sqliteCommand.ExecuteNonQuery();

'col1' 为 '1' 或 '2' 时不会删除行。

如果我将 SQL 更改为:

sqliteCommand.CommandText = @"delete from [test_table] where col1 in(@para1,@para2)";
sqliteCommand.Parameters.Add(new SqliteParameter("@para1", "1"));   
sqliteCommand.Parameters.Add(new SqliteParameter("@para2", "2"));

确实有效。

如果我将 SQL 更改为:

sqliteCommand.CommandText = @"delete from [test_table] where col1 in ('1', '2')";
sqliteCommand.ExecuteNonQuery();

有了这个,它也确实起作用了。

但是,如果我将 SQL 更改为:

delete from [test_table] where col1 in(@para1)   
sqliteCommand.Parameters.Add(new SqliteParameter("@para1", "'1','2'"));
//or sqliteCommand.Parameters.Add(new SqliteParameter("@para1", "1,2"));

在这种情况下,它不起作用。

我认为微软需要调查这个问题。

“Microsoft.Data.Sqlite”库的版本是 2.2.6。

以下是整个代码演示:

SqliteConnection sqliteConnection = new SqliteConnection("Filename=test.db");
sqliteConnection.Open();

SqliteDataReader sqliteDataReader;

string sql = @"CREATE TABLE IF NOT EXISTS [test_table] ( col1 VARCHAR(1), col2 VARCHAR(1), col3 VARCHAR(4));";

SqliteCommand sqliteCommand = new SqliteCommand(sql, sqliteConnection);
sqliteCommand.ExecuteNonQuery();

sql = @"INSERT INTO [test_table] (col1, col2, col3) VALUES('1', '1', '0001')";
sqliteCommand.CommandText = sql;

sqliteCommand.ExecuteNonQuery();

sql = @"INSERT INTO [test_table] (col1, col2, col3) VALUES('2', '2', '0002')";
sqliteCommand.CommandText = sql;
sqliteCommand.ExecuteNonQuery();

sql = @"INSERT INTO [test_table] (col1, col2, col3) VALUES('3', '3', '0003')";
sqliteCommand.CommandText = sql;
sqliteCommand.ExecuteNonQuery();

sqliteCommand.CommandText = @"delete from [test_table] where col1 in(@para1,@para2)";

//sqliteCommand.CommandText = @"delete from [test_table] where col1 in('1','2')";

sqliteCommand.Parameters.Add(new SqliteParameter("@para1", '1'));
sqliteCommand.Parameters.Add(new SqliteParameter("@para2", '2'));

sqliteCommand.ExecuteNonQuery();

sqliteCommand.CommandText = @"select * from [test_table]";
sqliteDataReader = sqliteCommand.ExecuteReader();

【问题讨论】:

  • 你的 SQLite 表中col1 的类型是什么?
  • '1' 在 SQL (string) 和 C# (char) 中是不同的。您可以尝试改用" 吗? ("@para1", "1"

标签: c# sqlite uwp


【解决方案1】:

直接回答

要允许使用 IN 删除可变数量的条目,请使用以下代码:

// Example data
var valuesToDelete = new List<string> { "1", "2", "4" };

sqliteCommand.CommandText = @"delete from [test_table] where col1 in(" + string.Join(",", Enumerable.Range(0, valuesToDelete.Count).Select(z => "@para" + z)) + ")";

for (var i = 0; i < valuesToDelete.Count; i++)
{
    sqliteCommand.Parameters.Add(new SqliteParameter("@para" + i, valuesToDelete[i]));
}

sqliteCommand.ExecuteNonQuery();

string.Join 用于在 SQL 中设置正确数量的参数,for 循环旨在填充这些参数。这允许在IN 中使用多个值,并且可以避免 SQL 注入。

背景

原因:

sqliteCommand.CommandText = @"delete from [test_table] where col1 in(@para1,@para2)";
sqliteCommand.Parameters.Add(new SqliteParameter("@para1", "1"));
sqliteCommand.Parameters.Add(new SqliteParameter("@para2", "2"));
sqliteCommand.ExecuteNonQuery();

有效但:

sqliteCommand.CommandText = @"delete from [test_table] where col1 in(@para1,@para2)";
sqliteCommand.Parameters.Add(new SqliteParameter("@para1", '1'));
sqliteCommand.Parameters.Add(new SqliteParameter("@para2", '2'));
sqliteCommand.ExecuteNonQuery();

不是因为后者你不小心将参数传递为char 而不是string

后者感觉是正确的,因为' 在SQL 中正常工作。但是 SQL 和 C# 是不同的 - ' 可以在 SQL 中围绕字符串使用,但不能在 C# 中使用(C# 使用 ' 表示 char" 表示 `string)。

因此,在传递字符串参数时 - 确保将它们传递为 string(使用 ")而不是 char

【讨论】:

    猜你喜欢
    • 2011-08-07
    • 1970-01-01
    • 2011-06-11
    • 2012-01-13
    • 1970-01-01
    • 2017-12-11
    • 1970-01-01
    • 2012-03-12
    相关资源
    最近更新 更多