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

时间:2017-10-20 08:41:07

标签: sql .net sql-server sql-injection

我必须将一个SQL字符串注入数据库,供第三方读取,执行,并使用结果进行报告。由于用户可以选择报告所需的列,以及重命名列,因此我最终得到了这样的代码:

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

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

我已经通过在有效列列表中检查它们来解决有关列名的部分,但我不能为别名做到这一点,别名可以是用户愿意给出的少于80个字符的字符串。

2 个答案:

答案 0 :(得分: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";

答案 1 :(得分:1)

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

正如您在评论中所述,您可能需要某些特殊字符支持,因此请特别转义这些特殊字符。

除此之外,您应该将允许的名称减少为字母数字字符和可能的空格。根据您选择的验证机制(例如regex)验证这些,并仅允许这些字符。这可能会让你大部分都免于SQL注入。

这不是最佳选择,但在这种情况下,它似乎是最好的。