C# FromSql():从字符串列表查询字符串生成以防止注入

C# FromSql():从字符串列表查询字符串生成以防止注入,c#,sql-server,.net-core,entity-framework-core,sql-injection,C#,Sql Server,.net Core,Entity Framework Core,Sql Injection,我正在EF Core中构建SQL搜索。Microsoft建议您不要使用concat字符串,因为它会使应用程序容易受到SQL注入的攻击,如Microsoft文档中所述: 始终对原始SQL查询使用参数化:除了 验证用户输入时,始终对使用的任何值使用参数化 在原始SQL查询/命令中。接受原始SQL字符串的API,例如 FromSql和ExecuteSqlCommand允许值作为 参数。接受的FromSql和ExecuteSqlCommand的重载 FormattableString还允许在 有助于防止

我正在EF Core中构建SQL搜索。Microsoft建议您不要使用concat字符串,因为它会使应用程序容易受到SQL注入的攻击,如Microsoft文档中所述:

始终对原始SQL查询使用参数化:除了 验证用户输入时,始终对使用的任何值使用参数化 在原始SQL查询/命令中。接受原始SQL字符串的API,例如 FromSql和ExecuteSqlCommand允许值作为 参数。接受的FromSql和ExecuteSqlCommand的重载 FormattableString还允许在 有助于防止SQL注入攻击的方法

如果使用字符串串联或插值来动态 生成查询字符串的任何部分,或将用户输入传递给 语句或存储过程,这些语句或存储过程可以作为 动态SQL,则您负责验证对的任何输入 防止SQL注入攻击

存储在此数据库中的信息不敏感,但显然我不想让数据库处于易受攻击状态

我有一个参数列表searchTerms,我需要遍历它并基于该列表构建一个查询

我将把字符串和SQL查询放在一起,但我只能看到如何通过连接来实现这一点。现在我的代码是这样的

var query = String.Format("SELECT ... where MySqlField like '%{0}%'", searchTerm[0]);

for (int i = 1; i < searchTerm.Count(); i++)
{
    query += String.Format(" and MySqlField like '%{0}%'", searchTerm[i]);
}

var results = context.MySqlTable.FromSql(query);
即使我使用插值,额外的验证是否足够?我遗漏了什么吗


是否有linq查询可以对列表执行相同的操作?

如果您使用EF,我建议您查看linq。使用原始字符串sql对于安全性和性能来说都不是一个好主意。LINQ提供了一种执行查询的健壮方法。只是在编写查询时要小心,因为LINQ可能会试图使查询过于复杂

编辑:

我错过了你文章的最后一行。很抱歉,以下内容将帮助您走上正确的道路:

for (var item in searchTerms) {
    query = query.Where(w => w.MySqlField.Contains(item.Value));
}

我目前无法测试它,因此我会让您知道这种方法

List<string> ph = new List<string>();
int count = 0;
foreach(string s in searchTerm)
{
    ph.Add($"MySqlField LIKE '%{{{count}}}%'");
    count++;
}

if(count > 0)
    query = query + " WHERE " + string.Join(" OR ", ph);
var results = context.MySqlTable.FromSql(query, searchTerm.ToArray());
虽然这看起来像是一种字符串连接方法,但我们可以在

虽然这看起来像String.Format语法,但提供的值是 包装在参数中,生成的参数名称插入其中 已指定{0}占位符

没有多少选择:

如果使用较新的SQL Server,则以XML或JSON传递值,然后编写静态XML/JSON查询

创建一个临时表,在临时表中插入所有搜索值,然后执行静态查询


您的代码应该足够好,只需稍加修改:

var query = String.Format("SELECT ... where 1=1 ");

for (int i = 0; i < searchTerm.Count(); i++)
{

    query += $" and MySqlField like '%'+{{{i}}}+'%'";
}

var results = context.MySqlTable.FromSql(query, searchTerm.ToArray());

FromSql有一个重载,允许您传递参数。你为什么不使用它呢?顺便说一句,在同一个字段上有多个和多个条件。您可能需要在此处使用或。@Steve我如何根据大小变化的列表将参数添加到FromSql重载中?如果要传递多个值,是否考虑使用表值参数?如果你不想使用TVP,你可以传递一个带分隔符的列表,然后使用字符串拆分器,比如string_SPLIT。不需要测试,我只是在寻找方法。我可以自己测试。可能通配符%和单引号中有问题需要解决。现在看来,我们在这里构建的是文本而不是参数占位符数字2显然是这个问题的正确答案。选项3:使用全文搜索。我本来会这样做的,但我想避免这样一种情况,即我通过多次迭代执行搜索,在这种情况下,我必须确保结果是不同的——这似乎是额外的不必要的开销。如果有任何可能的方法,我想执行一个查询。如果代码中没有更多的insite,我能为您提供的唯一帮助就是在运行此foreach之前将查询保留为iqueryable,我意识到我忘记了每个查询。它不会处理查询,除非您使用.ToList或任何您喜欢的方法将其转换或强制转换为。这样,您只需访问数据库一次。只要确保您的查询输入是不同的,您就可以使用searchTerms.distinct,而不需要太多实际的开销。虽然你可能想看看你的输入,看看为什么你会有倍数。这正是我在使用列表/数组作为字符串参数方面所寻找的。你能解释一下1=1的位置吗?@1=1是作为一个虚拟标准存在的,这样我就可以开始添加和。。。从循环的开始。