清理不可参数化 sql 的最佳方法

Best way of sanitize unparametrizable sql

提问人:Rekesoft 提问时间:10/20/2017 更新时间:10/20/2017 访问量:238

问:

我必须将一个SQL字符串注入到数据库中,以便第三方读取它,执行它,并用结果制作报告。由于用户可以选择报表所需的列,以及重命名列,因此我以如下代码结束:

string sql = "SELECT ";
foreach(KeyValuePair<string, string> field in report.fields)
{
    sql += "[" + field.Key + "] as [" + field.Value + "];
}
sql += " WHERE idrpt=@id";

我唯一可以参数化的查询部分是 WHERE 子句,但如果我在 Web 上的研究没有被误导,则无法参数化 SELECT 子句中的列名和别名。现在,鉴于我无法更改程序的工作方式(我必须向第三方生成有效的 SQL 查询才能执行它),清理输入字符串的最佳方法是什么?

我已经通过根据有效列列表检查列名来解决有关列名的部分,但我不能对别名这样做,别名可以是用户愿意提供的任何少于 80 个字符的字符串。

sql .net sql-server sql 注入

评论

0赞 Magisch 10/20/2017
这是一个很大的 X/Y 问题。一个答案是不要这样做,并更改您的程序设计以不需要它。
0赞 Magisch 10/20/2017
另一种方法是只允许字母数字 ascii 字符和指定的空格,然后对字符串进行转义
0赞 Rekesoft 10/20/2017
你错过了关于“我无法改变程序工作方式”的部分。这使您的评论成为 XY 的咆哮。顺便说一句,第二条评论更像是一种解决方案......我可以根据正则表达式限制名称别名上的有效字符。我会考虑一下。
0赞 Magisch 10/20/2017
我不明白有人如何合理地仅使用字母数字字符和空格进行 SQL 注入,因此这可能会防止这种情况发生。这样做的好处是,对列名和别名的限制也很有意义。
0赞 Rekesoft 10/20/2017
当然,但是虽然我们的大多数客户都使用西班牙语,但有些人使用英语、法语或加泰罗尼亚语,所以我不能排除文本中的单引号(撇号)。我想我可以只允许字母数字字符和单引号,然后只对单引号进行清理。

答:

1赞 Radim Bača 10/20/2017 #1

如您所指出的,无法参数化列名和别名。因此,你对 SQL 注入持开放态度。为了最大程度地减少问题,您可以使用 quotename,它类似于您当前使用的方法。

string sql = "SELECT ";
foreach(KeyValuePair<string, string> field in report.fields)
{
  sql += "quotename(" + field.Key + ") as quotename(" + field.Value + ")";
}
sql += " WHERE idrpt=@id";

评论

0赞 Rekesoft 10/20/2017
是的,这就是我现在使用的方法。事实上,我正在使用 QUOTENAME(“ + 字段。Value.Replace(“'”, “''”) + “)”,但我仍然不确定。
1赞 Magisch 10/20/2017 #2

是的,所以你有一个无法更改的 SQL 布局,这需要你这样做。这很不幸,但让我们充分利用它。

正如您在评论中所说,您可能需要一些特殊字符支持,因此请专门转义这些特殊字符。

除此之外,您应该将允许的名称减少到字母数字字符,并可能减少空格。根据您选择的验证机制(例如正则表达式)验证这些字符,并仅允许这些字符。这可能会使您免受SQL注入的影响。

这不是最佳选择,但在这种情况下,这似乎是你能做的最好的事情。