在 SQL Server 2016 中,我在存储过程中的 OLE-DB 链接服务器上运行复杂的动态 SQL 查询。
我目前正在将动态 SQL 构建为字符串,在许多地方连接参数。所以,我担心 SQL 注入。
链接服务器实际上是连接到 OSISoft PI 的 OLE-DB 提供程序接口,它是一个专门的历史数据库。我无法在 PI 中定义存储过程,因此我认为动态 SQL 是获得所需灵活性的唯一方法。
我确实使用该QUOTENAME(input, '''')
函数将用户提供的参数包装在引号中,这也应该转义输入中找到的任何引号。但我不确定这是否构成对 SQL 注入的有效防御。我这样做主要是因为它使字符串连接中的文字更简单。
存储过程当前看起来像这样:
-- Wrap user-supplied parameters in quotes to simplify SQL string building
DECLARE @Tag1 NVARCHAR(30) = QUOTENAME(@Tag1Input, '''')
DECLARE @Tag2 NVARCHAR(30) = QUOTENAME(@Tag2Input, '''')
DECLARE @Tag3 NVARCHAR(30) = QUOTENAME(@Tag3Input, '''')
DECLARE @Tag4 NVARCHAR(30) = QUOTENAME(@Tag4Input, '''')
DECLARE @Tag5 NVARCHAR(30) = QUOTENAME(@Tag5Input, '''')
DECLARE @Tag6 NVARCHAR(30) = QUOTENAME(@Tag6Input, '''')
DECLARE @Tag7 NVARCHAR(30) = QUOTENAME(@Tag7Input, '''')
DECLARE @Tag8 NVARCHAR(30) = QUOTENAME(@Tag8Input, '''')
DECLARE @Tag9 NVARCHAR(30) = QUOTENAME(@Tag9Input, '''')
DECLARE @Tag10 NVARCHAR(30) = QUOTENAME(@Tag10Input, '''')
DECLARE @starttimeq NVARCHAR(10) = QUOTENAME(@starttime, '''')
DECLARE @endtimeq NVARCHAR(10) = QUOTENAME(@endtime, '''')
DECLARE @timestepq NVARCHAR(10) = QUOTENAME(@timestep, '''')
DECLARE @calcbasisq NVARCHAR(30) = QUOTENAME(@calcbasis, '''')
-- Build SQL statement
DECLARE @sql NVARCHAR(2000) = 'SELECT tag, time, value
FROM piarchive..piavg
WHERE
tag IN (' + @Tag1 + ', ' + @Tag2 + ', ' +@Tag3 + ', ' + @Tag4 + ', ' + @Tag5 + ', ' + @Tag6 + ', ' + @Tag7+ ', ' + @Tag8 + ', ' + @Tag9 + ', ' + @Tag10 + ')
AND time BETWEEN ' + @starttimeq + ' AND ' + @endtimeq + '
AND timestep = ' + @timestepq + '
AND calcbasis = ' + @calcbasisq + '
UNION
SELECT ''calculatedValue'' AS tag, time, value
FROM piarchive..piavg
WHERE
expr = ''(''' + @Tag2 + ''' * (''' + @Tag3 + '''-''' + @Tag4 + ''') / (''' + @Tag2 + '''-''' + @Tag4 + ''') * 100.0 + ''' + @Tag5 + ''' * (''' + @Tag4 + '''-''' + @Tag1 + ''') / (''' + @Tag5 + '''-''' + @Tag1 + ''') * (''' +@Tag3 + '''-''' + @Tag2 + ''') / (''' + @Tag4 + '''-''' + @Tag2 + ''') * 100.0) / ((''' +@Tag3 + '''-''' + @Tag4 + ''') / (''' + @Tag2 + '''-''' + @Tag4 + ''') * 100.0 + (''' + @Tag4 + '''-''' + @Tag1 + ''') / (''' + @Tag5 + '''-''' + @Tag1 + ''') * (''' +@Tag3 + '''-''' + @Tag2 + ''') / (''' + @Tag4 + '''-''' + @Tag2 + ''') * 100.0)''
AND time BETWEEN ' + @starttimeq + ' AND ' + @endtimeq + '
AND timestep = ' + @timestepq + '
AND calcbasis = ' + @calcbasisq + '
ORDER BY time ASC, tag ASC'
-- Invoke dynamic SQL on PI OLEDB linked server
EXEC (@sql) AT PI
据我所知,我不能使用 sp_executesql 在 OLE-DB 链接服务器上运行查询。(如果我错了,请纠正我)。
由于 OLE-DB 的限制,EXEC(@sql, <params>) AT LinkedServer
语法似乎只支持位置参数。?
由于可怕的expr
过滤器子句,我真的想使用命名参数而不是位置参数。
当我不能使用 sp_executesql 或命名参数时,如何安全地准备这个 SQL 字符串以防止 SQL 注入攻击?有没有一种优雅的方法,或者我只需要使用 46 个位置参数(包括许多重复)来强制它?