为什么String.Format可行,而SqlCommand.Parameters.Add却不行?

7

我有一个Project表格,包含两列--ProjectIdProjectName--我正在编写一个函数,构建并执行一个SqlCommand来查询具有给定名称的项目的ID。这个命令可以工作,但容易受到SQL注入的攻击:

string sqlCommand = String.Format("SELECT {0} FROM {1} WHERE {2} = {3}",
            attributeParam, tableParam, idParam, surroundWithSingleQuotes(idValue));

SqlCommand command = new SqlCommand(sqlCommand, sqlDbConnection);
using (SqlDataAdapter adapter = new SqlDataAdapter(command))
{
    DataTable attributes = new DataTable();
    adapter.Fill(attributes);
    ...
}
attributeParamtableParamidParamidValue都是字符串,例如:"ProjectId""Project""ProjectName""MyFirstProject"surroundWithSingleQuotes会使用''将字符串括起来,因此surroundWithSingleQuotes(idValue) == "'MyFirstProject'"。我试图尽可能地编写通用的函数,因为我将来可能需要从表中获取给定属性的全部内容。

虽然上面的String.Format可以工作,但这个却不行:

string sqlCommand = String.Format("SELECT @attributeparam FROM {0} WHERE " + 
    "@idparam = @idvalue", tableParam);

command.Parameters.Add(new SqlParameter("@attributeparam", attributeParam));
command.Parameters.Add(new SqlParameter("@idparam", idParam));
command.Parameters.Add(new SqlParameter("@idvalue", 
     surroundWithSingleQuotes(idValue)));

SqlCommand command = new SqlCommand(sqlCommand, sqlDbConnection);
using (SqlDataAdapter adapter = new SqlDataAdapter(command))
{
    DataTable attributes = new DataTable();
    adapter.Fill(attributes);
    ...
}

我不确定为什么会这样。我没有收到任何错误信息,但是当我使用SqlDataAdapter填充我的DataTable时,DataTable为空。以下是我尝试过的各种方法,但都无济于事:
  • 根据此答案Microsoft文档,使用AddWithValue或使用Parameters.Add和SqlParameter.Value。
  • 有选择地替换String.Format中的{0}、{1}、{2}和{3},用实际值或参数字符串替换。
在我的代码的其他地方,我已经成功使用了带有参数的查询(虽然只是一个参数)。

2
唯一可以直接替换的参数是 {3} - Scott Chamberlain
2
你不能使用参数作为列名。对于这个,你仍然需要像表名一样使用 string.Format - juharr
2个回答

7
基本上,SQL中的参数只适用于 - 而不是列或表的标识符。在您的示例中,只有最后一个参数表示值。
如果您需要根据列和表名动态执行操作,则需要自己构建SQL语句的这部分。由于与SQL注入攻击相关的所有正常原因,请非常小心。最好只允许已知白名单中的表和列值。如果需要更通用,建议进行非常严格的验证,并引用标识符以避免与关键字冲突(或理想情况下完全禁止)。
当然,继续使用SQL参数来传递值。

0

这是一个有效的语句:SELECT * FROM SomeTable WHERE SomeColumn=@param

而这个不是:SELECT * FROM @param

这意味着您可以为值(如参数)使用参数,但不能为表名、视图名、列名等使用参数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接