我有一个存储过程,它有许多参数(所有varchar),一些参数用在where子句中,其他参数用作表名。我读过许多文章,建议使用引号来表名,转义单引号,%和_以及白名单或黑名单字或字符。
在我的情况下,引号不起作用,因为添加[]会中断我的过程,因为我使用sys.tables,其中name = @tablename来验证从sys.columns获取列。
所以我决定创建一个泛型函数来验证参数以避免SQL注入...这个简单的函数接受@input参数并返回@input变量的修改版本(如果找到不需要的字符)。当找到以下字符(或单词)时,此函数使用replace命令:
' - / * * /%; + [UNION DROP CREATE INSERT SELECT UPDATE UNION
我构建的函数如下所示:
CREATE function [dbo].[AntiSQLInjection] (@input varchar(8000))
Returns varchar(8000)
As
Begin
Return
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(
replace(@input,
'''',''''''),
'UNION',''),
'--',''),
'/*',''),
'*/',''),
'DROP ',''),
'ALTER ',''),
'CREATE ',''),
'%','[%]'),
'[','[[]'),
';',''),
'+',''),
'SELECT ',''),
'UPDATE ',''),
'INSERT ',''),
'DELETE ','')
End
我无法摆脱动态SQL ...我的问题是“这个函数是否覆盖了所有不同的角度以避免SQL注入?”
以下是一些使用参数的代码示例,我将使用AntiSQLInjection函数解析参数:
SET @SQLStr = ' SELECT c.name, CASE WHEN y.name IS NOT NULL THEN 1 ELSE 0 END AS Set_Columns
INTO TMP_Col
FROM sys.tables t
JOIN sys.columns c on c.object_id = t.object_id
JOIN (SELECT c.name
FROM sys.tables t
JOIN sys.columns c ON c.object_id = t.object_id
WHERE t.name = ''' + @tar_local + ''') x ON x.name = c.name
LEFT JOIN (SELECT c.name
FROM sys.tables t
JOIN sys.columns c ON c.object_id = t.object_id
WHERE t.name = ''' + @tar_local + ''') y ON y.name = c.name and y.name in (''' + CASE WHEN @set_local IS NULL THEN 'No Set Parameter' ELSE REPLACE(@set_local,';',''',''') END + ''')
WHERE t.name = ''TMP_9999999'''
EXEC (@SQLStr)
SET @SQLStr = 'INSERT INTO TMP_PK_TAB_9999999 (TABLE_QUALIFIER, TABLE_OWNER, TABLE_NAME, COLUMN_NAME,KEY_SEQ, PK_NAME)
EXEC sp_pkeys ''' + @tar_local + ''''
EXEC (@SQLStr)
而且更复杂 - > params是@tar_local,@ src_local,@ key_local ......其他变量是SP中构建的字符串,我并不担心。
SET @SQLStr = 'INSERT INTO ' + @tar_local + '(' + @ColumnsStr + ') SELECT S.' + REPLACE(@ColumnsStr,',',',S.') + ' FROM (' + @src_local + ') S LEFT JOIN ' + @tar_local + ' T ON T.' + REPLACE(REPLACE(REPLACE(@key_local,' ',''),'=:','= S.'),'AND',' AND T.') +
' WHERE T.' + SUBSTRING(@ColumnsStr,PATINDEX('%F%',@ColumnsStr), CASE WHEN PATINDEX('%,%',@ColumnsStr) = 0 THEN LEN(@ColumnsStr)-PATINDEX('%F%',@ColumnsStr) ELSE PATINDEX('%,%',@ColumnsStr) - PATINDEX('%F%',@ColumnsStr) END) + ' IS NULL'
EXEC(@SQLStr)
我知道这不是最干净的方式,如果您有任何其他想法,请随时分享。
提前感谢。