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

问题描述:

我必须将一个SQL字符串注入数据库*第三方读取,执行它并使用结果生成报告。由于用户可以选择列通缉的报告,以及重命名列,我已经有这样的代码结束:清理不可参数化的sql的最佳方式

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

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

我已经解决了关于列名称的部分,通过检查列表的有效列,但我不能这样做的别名,可以是任何小于80个字符的字符串用户愿意给。

+0

这是一个很大的X/Y问题。一个答案是不要这样做,并改变你的程序设计不需要这个。 – Magisch

+0

另一种方法是仅允许字母数字ASCII字符和指定的空白字符,然后也可以转义字符串 – Magisch

+0

您错过了关于“我无法改变程序工作方式”的部分。这让你的评论成为XY咆哮的一大提示。顺便提一句,更多的解决方案是......我可以将名称别名上的有效字符限制为正则表达式。我会给它一个想法。 – Rekesoft

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

正如你在你的评论中所述,你可能需要一些特殊字符的支持,所以特意转义这些特殊字符。

除此之外,您应该将允许的名称缩小为字母数字字符和可能的空格。根据您选择的验证机制验证这些机制,例如正则表达式,并仅允许这些字符。这可能会让你几乎免于SQL注入。

这不是最佳,但它似乎是你在这种情况下可以做的最好的。

正如您所指出的那样,没有办法参数化列名和别名。因此,您打开SQL注入。为了最大限度地减少问题,您可以使用quotename,这与您当前使用的方法类似。

string sql = "SELECT "; 
foreach(KeyValuePair<string, string> field in report.fields) 
{ 
    sql += "quotename(" + field.Key + ") as quotename(" + field.Value + ")"; 
} 
sql += " WHERE [email protected]"; 
+0

是的,这是我现在使用的最新方法。事实上,我使用QUOTENAME(“+ field.Value.Replace(”'“,”''“)+”)“,但我仍然不确定。 – Rekesoft

+0

不错,那么我猜你没有太多可以做得更多。 –