提问人:Nathan L 提问时间:12/10/2019 最后编辑:Dale KNathan L 更新时间:12/10/2019 访问量:91
保护动态 SQL 免受 SQL 注入的影响
Securing Dynamic SQL from SQL Injection
问:
我有一个动态脚本在数据库中的所有对象上运行,并将每个对象的架构名称从 [dbo] 更改为数据库名称。
脚本运行良好,我想知道我是否可以做得更好,以保护它免受SQL注入的影响?
BEGIN TRANSACTION
/* Change schema to all objects in database (from dbo)*/
DECLARE @SchemaName SYSNAME = db_name();
DECLARE @SQL NVARCHAR(MAX) = N'IF Not Exists (select 1 from sys.schemas where schema_id = SCHEMA_ID(@NewSchemaName))
EXEC(''CREATE SCHEMA ''+@NewSchemaName+'''')' + NCHAR(13) + NCHAR(10);
SELECT @SQL = @SQL + N'EXEC(''ALTER SCHEMA ''+@NewSchemaName+'' TRANSFER [' + SysSchemas.Name + '].[' + DbObjects.Name + ']'');' + NCHAR(13) + NCHAR(10)
FROM sys.Objects DbObjects
INNER JOIN sys.Schemas SysSchemas
ON DbObjects.schema_id = SysSchemas.schema_id
WHERE SysSchemas.Name = 'dbo'
AND (DbObjects.Type IN ('U', 'P', 'V'))
EXECUTE sp_executesql @sql, N'@NewSchemaName sysname', @NewSchemaName = @SchemaName
ROLLBACK
为了保护这一点,我使用了 Thom Andrews 的这篇精彩文章:动态 SQL 的注意事项
这就是我开始的地方:github.com/NathanLifshes
答:
0赞
Guy Glantser
12/10/2019
#1
在这种情况下,我没有看到 SQL 注入的实际风险,因为用户没有提供任何值。该脚本仅将数据库名称作为输入。利用 SQL 注入的唯一选择是将命令注入数据库名称。当然,这是可能的。为了防止出现此选项,应使用 QUOTENAME 函数在动态脚本中正确引用架构名称。
评论
0赞
Nathan L
12/10/2019
假设我们想使用此代码并从用户那里获取新的架构名称:-)
1赞
Eitan Blumin
12/10/2019
#2
下面的脚本应该更安全。 请注意脚本开头的 QUOTENAME 函数的使用。 这将起作用,因为如果在 EXEC 命令中使用 QUOTENAME 函数“内联”,则可能会出现语法错误。因此,您需要在早期阶段应用它。 幸运的是,当您初始化 @SchemaName 变量时,您有一个“更早”的阶段:
BEGIN TRANSACTION
/* Change schema to all objects in database (from dbo)*/
DECLARE @SchemaName SYSNAME = QUOTENAME(db_name());
DECLARE @SQL NVARCHAR(MAX) = N'IF Not Exists (select 1 from sys.schemas where schema_id = SCHEMA_ID(@NewSchemaName))
EXEC(''CREATE SCHEMA ''+@NewSchemaName+'''')' + NCHAR(13) + NCHAR(10);
SELECT @SQL = @SQL + N'EXEC(''ALTER SCHEMA ''+@NewSchemaName+'' TRANSFER ' + QUOTENAME(SysSchemas.Name) + '.' + QUOTENAME(DbObjects.Name) + ''');' + NCHAR(13) + NCHAR(10)
FROM sys.Objects DbObjects
INNER JOIN sys.Schemas SysSchemas
ON DbObjects.schema_id = SysSchemas.schema_id
WHERE SysSchemas.Name = 'dbo'
AND (DbObjects.Type IN ('U', 'P', 'V'))
PRINT @SQL
EXECUTE sp_executesql @sql, N'@NewSchemaName sysname', @NewSchemaName = @SchemaName
ROLLBACK
评论
QUOTENAME
'...[' + SysSchemas.Name + ']...'
'...' + QUOTENAME(SysSchemas.Name) + '...'
ALTER SCHEMA
@NewSchemaName
QUOTENAME
ALTER
]
'['
']'
EXEC
命令”为什么要在动态 SQL 中创建动态 SQL?