我在whereclause中使用了参数,但是这个{0}
的变量呢。我是否需要为它创建一个参数来阻止sql注入?
("...inner join db1.dbo.table1.id on db2.dbo.table2.id = {0}.dbo.table3.id where name=@name",abc)
var abc = ddl2.SelectedItem.Text;
cmd.Parameters.AddWithValue("@name", ddl1.selectedvalue);
答案 0 :(得分:3)
据我所知,您实际上不能“对数据库名称/表名称进行'参数化”。
在这种情况下,String.Format不解决SQL注入,因为用户可以将ddl2.SelectedItem.Text
更改为他们想要的任何内容。
如果您需要数据库名称的动态值,我建议您将该值保留为const
或将其存储在您完全控制/从未发送或解释客户端的位置。
答案 1 :(得分:0)
我建议您使用任何ORM(对象关系映射),即实体框架或n-hibernate等,并使用linq编写查询,这将阻止您从SQL注入应用程序。
答案 2 :(得分:0)
不幸的是,正如Abbath已经提到的,这种类型的构造不可参数化。正如阿巴斯所提到的,最好的解决方案是将这些论点置于你的绝对控制之下,但有时候需要这样的结构,并且可能无法完全控制它们。
对于这种情况,在这种情况下,最好的建议是逃避争论。在这种情况下,示例代码上由{0}
表示的数据库名称。
有两种可能的机制来实现这一目标:
a)创建一种允许您参数化查询的机制
优点:您可以从任何驱动程序(.Net,ODBC等)重用相同的解决方案
缺点:多一点工作。在这种情况下,您将不再使用select。
例如(我包含一个内部联接的简单示例,就像您的代码一样):
CREATE PROC sp_MyQuery( @target_db_name sysname, @name nvarchar(100))
AS
BEGIN
DECLARE @cmd nvarchar(max)
DECLARE @parameters nvarchar(max)
SELECT @cmd = N'SELECT * FROM msdb.sys.objects inner join '
+ quotename(@target_db_name) + N'.sys.sql_modules
on msdb.sys.objects.object_id = '
+ quotename(@target_db_name) + N'.sys.sql_modules.object_id WHERE name = @name'
print @cmd -- See the command before it is executed.
set @parameters = N'@name nvarchar(100)'
EXEC sp_executesql @cmd, @parameters, @name = @name
END
go
-- Example of usage
DECLARE @target_db_name sysname = 'msdb'
DECLARE @name nvarchar(100) = 'sp_help_operator'
EXEC sp_MyQuery @target_db_name, @name
go
此时,您可以像平常一样使用SqlParameter
个对象。例如:
sqlcmd.CommandText = @"[dbo].[sp_MyQuery]";
sqlcmd.CommandType = System.Data.CommandType.StoredProcedure;
sqlcmd.Parameters.AddWithValue("@target_db_name", ddl0.selectedvalue);
sqlcmd.Parameters.AddWithValue("@name", ddl1.selectedvalue);
SqlDataReader reader = sqlcmd.ExecuteReader();
b)转义CLR代码中的DB名称
优势:更容易实施
缺点:特定于应用程序的解决方案,您需要注意潜在的Unicode-DB整理翻译问题。
例如(与上述相同的查询):
sqlcmd.CommandText = String.Format(@"
SELECT * FROM msdb.sys.objects inner join [{0}].sys.sql_modules on msdb.sys.objects.object_id = [{0}].sys.sql_modules.object_id WHERE name = @name;",
ddl0.selectedvalue.Replace("]", "]]"));
sqlcmd.CommandType = System.Data.CommandType.Text;
sqlcmd.Parameters.AddWithValue("@name", ddl1.selectedvalue);
SqlDataReader reader2 = sqlcmd.ExecuteReader();
我通常建议尽可能使用解决方案(a),但这两种解决方案都可以帮助您防止SQL注入。
顺便说一句。以下链接也非常有用:https://blogs.msdn.microsoft.com/raulga/2007/01/04/dynamic-sql-sql-injection/
我希望信息有所帮助。
答案 3 :(得分:-2)
var abc = ddl2.SelectedItem.Text;
string.format("...inner join db1.dbo.table1.id on db2.dbo.table2.id = {0}.dbo.table3.id where name=@name",abc)
cmd.Parameters.AddWithValue("@name", ddl1.selectedvalue);