参数和SQL注入asp.net
Parameters and SQL Injection asp.net
我在 where 子句中使用了参数,但是这个 {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);
如果像这样使用 string.format,则不需要为 abbc 创建参数
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);
我建议您使用任何 ORM(对象关系映射),即 Entity framework 或 n-hibernate 等,并使用 linq 编写查询,这将防止您的应用程序受到 SQL 注入。
据我所知,您实际上无法 'paramaterize' 数据库 names/table 名称。
在这种情况下,String.Format 无法解决 SQL 注入问题,因为用户可以将 ddl2.SelectedItem.Text
更改为他们想要的任何内容。
如果您需要数据库名称的动态值,我建议您将该值保留为 const
或将其存储在您可以完全控制/永远不会发送或解释客户端的某个地方。
不幸的是,正如 Abbath 已经提到的,这种类型的结构不可参数化。正如 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 代码中转义数据库名称
优点:更容易实施
缺点:特定于应用程序的解决方案,您需要小心潜在的 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 注入。
顺便说一句。以下 link 可能也很有用:https://blogs.msdn.microsoft.com/raulga/2007/01/04/dynamic-sql-sql-injection/
希望信息对您有所帮助。
我在 where 子句中使用了参数,但是这个 {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);
如果像这样使用 string.format,则不需要为 abbc 创建参数
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);
我建议您使用任何 ORM(对象关系映射),即 Entity framework 或 n-hibernate 等,并使用 linq 编写查询,这将防止您的应用程序受到 SQL 注入。
据我所知,您实际上无法 'paramaterize' 数据库 names/table 名称。
在这种情况下,String.Format 无法解决 SQL 注入问题,因为用户可以将 ddl2.SelectedItem.Text
更改为他们想要的任何内容。
如果您需要数据库名称的动态值,我建议您将该值保留为 const
或将其存储在您可以完全控制/永远不会发送或解释客户端的某个地方。
不幸的是,正如 Abbath 已经提到的,这种类型的结构不可参数化。正如 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 代码中转义数据库名称
优点:更容易实施
缺点:特定于应用程序的解决方案,您需要小心潜在的 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 注入。
顺便说一句。以下 link 可能也很有用:https://blogs.msdn.microsoft.com/raulga/2007/01/04/dynamic-sql-sql-injection/
希望信息对您有所帮助。