为什么字符串.格式工作,但SqlCommand.Parameters.Add不

本文关键字:SqlCommand Parameters Add 字符串 格式 工作 为什么 | 更新日期: 2023-09-27 18:17:49

我有一个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 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不包含任何内容。以下是我采取的各种方法,但都无济于事:

  • 遵循这个答案和微软的文档,使用AddWithValue或使用Parameters.AddSqlParameter.Value
  • 选择性地将String.Format中的{0}{1}{2}{3}替换为实际值或参数字符串。

在我代码的其他地方,我使用了参数化查询(尽管只有一个参数),没有问题。

为什么字符串.格式工作,但SqlCommand.Parameters.Add不

基本上SQL中的参数只适用于 -而不是列或表的标识符。在您的示例中,只有最后一个参数表示一个值。

如果您需要在列名和表名方面是动态的,那么您需要自己构建这部分SQL。由于所有与SQL注入攻击相关的正常原因,请非常小心。理想情况下,只允许已知的表和列值的白名单。如果您需要更通用,我建议执行非常严格的验证,并引用标识符以避免与关键字冲突(或者理想情况下完全禁止这些)。

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

而这不是:SELECT * FROM @param

这意味着你可以使用参数值,而不是表名,视图名,列名等。