【发布时间】:2022-01-20 17:00:33
【问题描述】:
当导入/解析平面文件和分隔数据时(我们使用SqlBulkCopy),我们最终会得到一个包含 DATA_KEY 和 DATA_VAL 列的表。 [EDIT] 忘了说这个表是.net crl 的工作表,只解析各种入站数据。要将数据从该工作表加载到生产表中,我们然后使用动态查询来 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 标识符;那里可以打针吗?
只是想确保所有的基地都被覆盖;欢迎 cmets 和建议!
【问题讨论】:
-
a table with a DATA_KEY and DATA_VAL column.不要使用这样的表格。该提议根本没有任何好处(当然没有“灵活性”),同时几乎不可能进行查询。当值完全不相关时,索引是无用的,值验证是不可能的,缓冲效率会大大降低,因为从表中加载的 lot 数据将用于不相关的“实体”。外键是不可能的。这是错误,不是聚合列名。 -
将 QUOTENAME() 包裹在列名周围,这将保护您至少在该特定位置免受任何可能的注入。请参阅 mssqltips.com/sqlservertip/3637/… 和 mssqltips.com/sqlservertip/3638/… 另外,如果您在 2017 年以上,请查看 STRING_AGG,它比 FOR XML PATH 更容易查看...
-
您也可以在盲目地将DATA_KEY放入CASE表达式之前检查是否在sys.columns中。这确实将风险降低到几乎为零。
-
您需要在
CASE部分还需要QUOTENAME...CASE DATA_KEY WHEN ' + QUOTENAME(DATA_KEY, '''') + ' THEN...您还需要更改您的FOR XML以使用.value以取消转义XML 字符。如果您有 SQL Server 2017+,只需使用STRING_AGG -
不使用额外的参数
QUOTENAME(..., ''''),这将导致'FOO'见dbfiddle.uk/…
标签: sql-server tsql dynamic-sql