我有一个Project
表,其中包含两列 - ProjectId
和ProjectName
- 我正在编写一个函数来构造并执行SqlCommand
来查询数据库具有给定名称的项目的ID。此命令有效,但容易受到SQL Injection:
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);
...
}
attributeParam
,tableParam
,idParam
和idValue
都是字符串。例如,它们可能分别是"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);
...
}
我不确定为什么。我没有收到任何错误消息,但是当我使用DataTable
填充SqlDataAdapter
时,DataTable不包含任何内容。以下是我采取的各种方法,但无济于事:
AddWithValue
或使用Parameters.Add
和SqlParameter.Value
。 {0}
中的{1}
,{2}
,{3}
和String.Format
。 在我的代码的其他地方,我使用参数化查询(虽然只有一个参数)没问题。
答案 0 :(得分:7)
SQL中的参数基本上只适用于值 - 而不是列或表的标识符。在您的示例中,只有最终参数表示值。
如果您需要在列名和表名方面保持动态,那么您需要自己构建SQL的那一部分。 非常小心,因为与SQL注入攻击相关的所有正常原因。理想情况下,只允许表和列值的已知白名单。如果您需要更一般,我建议执行非常严格的验证,quote the identifiers以避免与关键字发生冲突(或完全禁止这些冲突)。
当然,继续使用SQL参数作为值。
答案 1 :(得分:0)
这是一个有效的声明:
SELECT * FROM SomeTable WHERE SomeColumn=@param
虽然这不是:
SELECT * FROM @param
这意味着您可以使用值的参数,而不是表名,视图名,列名等。