T-SQL动态枢轴查询和SQL注入保护
T-SQL Dynamic pivot query and SQL Injection protection
当 importing/parsing 平面文件和分隔数据(我们对这些使用 SqlBulkCopy
)时,我们最终得到 table 和 DATA_KEY 和 DATA_VAL柱子。 [编辑] 忘了提这个 table 是 .net crl 的工作 table 仅解析各种入站数据。为了将这项工作 table 中的数据加载到生产 tables 中,我们然后使用动态查询来 PIVOT 数据,如下所示:
DECLARE @sqlCommand varchar(MAX)
DECLARE @columnList varchar(max)
SELECT
@columnList = STUFF((SELECT DISTINCT',MIN(CASE DATA_KEY WHEN '''+DATA_KEY+''' THEN DATA_VAL END) AS '+ QUOTENAME(DATA_KEY)
FROM PARSED_DATA
FOR XML PATH ('')), 1, 1, '')
SET @sqlCommand = 'SELECT ROW_NUMBER() OVER(ORDER BY KEYID,PARENT_POS) AS ROWID, ' + @columnList + ' FROM PARSED_DATA
这工作正常,但带来了可能的 SQL 注入问题。显然这是一个连接的字符串,因此 DATA_KEY 和 DATA_VAL 可能会被注入。当我查看 DATA_KEY 字段时,似乎唯一可行的方法是如果攻击者知道这是在 CASE 语句中——也就是说,注入的代码必须正确地结束 CASE 语句或整个查询会失败。同样,如果注入没有正确结束 CASE 语句,DATA_VAL 字段将使整个查询失败。
我说得对吗?还是我错过了一些明显的东西?另外,在 DATA_KEY 用作列名的地方我们容易受到影响吗? QUOTENAME 使该值成为有效的 SQL 标识符;那里可以打针吗?
只是想确保所有基地都被覆盖;欢迎提出意见和建议!
我可以看到一些问题:
- 您还应该在主元
CASE
表达式上使用 QUOTENAME
。使用 ''''
作为第二个参数,得到 ''
作为分隔符
FOR XML
应该使用 .value
来转义 XML 个字符
STUFF
的第三个参数是长度。为确保它始终正确,请使用 @separator
变量
- 动态SQL应该在
nvarchar(max)
DISTINCT
在计算字段上的性能可能很慢,首先在派生的 table/subquery 中分组可能更明智
DECLARE @separator nvarchar(10) = ',';
DECLARE @columnList nvarchar(max) = STUFF(
(SELECT @separator + 'MIN(CASE DATA_KEY WHEN ' + QUOTENAME(DATA_KEY, '''') + ' THEN DATA_VAL END) AS ' + QUOTENAME(DATA_KEY)
FROM (SELECT DISTINCT DATA_KEY FROM PARSED_DATA) pd
FOR XML PATH (''), TYPE
).value('text()[1]','nvarchar(max)'), 1, LEN(@separator), '');
你说你正在使用它来生成一个 INSERT
语句,所以你还应该根据 sys.columns
检查列名
当 importing/parsing 平面文件和分隔数据(我们对这些使用 SqlBulkCopy
)时,我们最终得到 table 和 DATA_KEY 和 DATA_VAL柱子。 [编辑] 忘了提这个 table 是 .net crl 的工作 table 仅解析各种入站数据。为了将这项工作 table 中的数据加载到生产 tables 中,我们然后使用动态查询来 PIVOT 数据,如下所示:
DECLARE @sqlCommand varchar(MAX)
DECLARE @columnList varchar(max)
SELECT
@columnList = STUFF((SELECT DISTINCT',MIN(CASE DATA_KEY WHEN '''+DATA_KEY+''' THEN DATA_VAL END) AS '+ QUOTENAME(DATA_KEY)
FROM PARSED_DATA
FOR XML PATH ('')), 1, 1, '')
SET @sqlCommand = 'SELECT ROW_NUMBER() OVER(ORDER BY KEYID,PARENT_POS) AS ROWID, ' + @columnList + ' FROM PARSED_DATA
这工作正常,但带来了可能的 SQL 注入问题。显然这是一个连接的字符串,因此 DATA_KEY 和 DATA_VAL 可能会被注入。当我查看 DATA_KEY 字段时,似乎唯一可行的方法是如果攻击者知道这是在 CASE 语句中——也就是说,注入的代码必须正确地结束 CASE 语句或整个查询会失败。同样,如果注入没有正确结束 CASE 语句,DATA_VAL 字段将使整个查询失败。
我说得对吗?还是我错过了一些明显的东西?另外,在 DATA_KEY 用作列名的地方我们容易受到影响吗? QUOTENAME 使该值成为有效的 SQL 标识符;那里可以打针吗?
只是想确保所有基地都被覆盖;欢迎提出意见和建议!
我可以看到一些问题:
- 您还应该在主元
CASE
表达式上使用QUOTENAME
。使用''''
作为第二个参数,得到''
作为分隔符 FOR XML
应该使用.value
来转义 XML 个字符STUFF
的第三个参数是长度。为确保它始终正确,请使用@separator
变量- 动态SQL应该在
nvarchar(max)
DISTINCT
在计算字段上的性能可能很慢,首先在派生的 table/subquery 中分组可能更明智
DECLARE @separator nvarchar(10) = ',';
DECLARE @columnList nvarchar(max) = STUFF(
(SELECT @separator + 'MIN(CASE DATA_KEY WHEN ' + QUOTENAME(DATA_KEY, '''') + ' THEN DATA_VAL END) AS ' + QUOTENAME(DATA_KEY)
FROM (SELECT DISTINCT DATA_KEY FROM PARSED_DATA) pd
FOR XML PATH (''), TYPE
).value('text()[1]','nvarchar(max)'), 1, LEN(@separator), '');
你说你正在使用它来生成一个 INSERT
语句,所以你还应该根据 sys.columns