sp_executesql保护动态搜索关键字
我试图将SQL语句转换为支持sp_executesql以使其安全,但我遇到了一个不安全的区域。希望你们能帮我。我创建了临时表,以便更容易地演示问题 问题出在第6步。我可以使用第5步,但这不安全,很容易被黑客攻击。我真的不想因为系统性能的原因而打断关键字并多次搜索sp_executesql保护动态搜索关键字,sql,sql-server,Sql,Sql Server,我试图将SQL语句转换为支持sp_executesql以使其安全,但我遇到了一个不安全的区域。希望你们能帮我。我创建了临时表,以便更容易地演示问题 问题出在第6步。我可以使用第5步,但这不安全,很容易被黑客攻击。我真的不想因为系统性能的原因而打断关键字并多次搜索 MS SQL 2008 Msg 4145,级别15,状态1,第4行出现错误。在预期条件的上下文中,在“顺序”附近指定了非布尔类型的表达式 GO /****** Object: StoredProcedure [dbo].[ups_Mu
MS SQL 2008 Msg 4145,级别15,状态1,第4行出现错误。在预期条件的上下文中,在“顺序”附近指定了非布尔类型的表达式
GO
/****** Object: StoredProcedure [dbo].[ups_MultiWareHouse] Script Date: 06/14/2012 09:12:38 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO
create PROCEDURE ups_TestSearch(
@Keywords nvarchar(4000),
@SortColumns nvarchar(4000)
)
AS
--STEP #1 - Create Temp Table - Begin
CREATE TABLE #TempTable
(
ProductID uniqueidentifier,
ProductName varchar(600),
Price decimal(18,2),
Active bit
)
--STEP #2 - Insert couple records to search
INSERT INTO #TempTable (ProductID,ProductName,Price,Active) VALUES(NEWID(),'Mouse','10.12','1')
INSERT INTO #TempTable (ProductID,ProductName,Price,Active) VALUES(NEWID(),'Keyboard','20.45','1')
INSERT INTO #TempTable (ProductID,ProductName,Price,Active) VALUES(NEWID(),'Monitor','150.87','0')--Disable this product
--STEP #3 - Display the current table data
select 'STEP #3' as STEP, * FROM #TempTable
--STEP #4 - SETTING UP sp_executesql to support parameter substitution
--Set definition
DECLARE @ParmDefinition nvarchar(4000);
SET @ParmDefinition='
@Param1ProductName nvarchar(4000),
@Param2SortColumns nvarchar(4000)
'
DECLARE @SQLString nvarchar(4000);
--STEP #5- CONVERT THE @SQLString TO use @Keywords and @SortColumns
--Run query for the below like this ups_TestSearch'ProductName=''Mouse'' OR ProductName=''Keyboard''', 'Price DESC, ProductName ASC'
SET @SQLString = N'SELECT ''STEP #5'' as STEP, #TempTable.* FROM #TempTable WHERE ('+@Keywords+') ORDER BY '+@SortColumns;--unsafe, open to hackers
EXECUTE sp_executesql @SQLString, @ParmDefinition, @Param1ProductName = @Keywords, @Param2SortColumns=@SortColumns;
--STEP #6- CONVERT THE @SQLString TO use @Keywords and @SortColumns
--Run query for the below like this ups_TestSearch'ProductName=''Mouse'' OR ProductName=''Keyboard''', 'Price DESC, ProductName ASC'
SET @SQLString = N'SELECT ''STEP #6'' as STEP, #TempTable.* FROM #TempTable WHERE (@Param1ProductName) ORDER BY @SortColumns';--Safe but not working
SELECT @SQLString AS SeeStatement
EXECUTE sp_executesql @SQLString, @ParmDefinition, @Param1ProductName = @Keywords, @Param2SortColumns=@SortColumns;
--Drop temp table
DROP TABLE #TempTable
我认为问题在于,在第5步中,您没有使用参数替换,也就是说,您基本上是通过字符串连接来构建SQL语句。当您通过sp_executesql执行它时,您实际上可以这样做:
EXECUTE sp_executesql @SqlString
步骤6中的代码正在执行参数替换。但是,在这种情况下,您只能在“普通”SQL表达式中允许使用参数的位置使用参数。例如,您不能在t-SQL中执行此操作:
DECLARE @Criteria NVARCHAR(500);
SET @Criteria = N' WHERE ProductName = ''Mouse'''
SELECT * FROM #MyTempTable + @Criteria
根据过滤器的复杂程度,您可以将条件写入临时表,并执行临时表的联接,以限制返回的结果数据。我不知道如何最好地对结果数据进行排序,除非您在调用代码中这样做了。您的错误消息表明步骤6中的
WHERE
子句无效,ORDER BY
子句也无效。这是因为您正在将字符串作为参数传递给sp_executesql
,并试图将它们用作整个子句。此外,该语句引用了一个参数@SortColumns
,但您似乎已将该参数命名为@Param2SortColumns
了解一些SQL server MVP编写的内容:
更重要的是:
我看不到一种简单的方法来改变您的过程来实现这一点,因为您将整个WHERE
和orderby
子句作为参数传递。你真正应该做的是重新设计程序。将每个WHERE
标准作为单个参数提供给ups\u TestSearch
。将每个WHERE
参数重新提供给sp_executesql
,并以这种方式构造初始SQL语句:
SET @SQLString = SELECT and JOIN portions of command
SET @SQLString = @SQLString + 'WHERE 1 = 1 '
IF (@WhereParam1 IS NOT NULL)
SET @SQLString = @SQLString + 'AND (SomeTable.SomeColumn = @WhereParam1) '
IF (@WhereParam2 IS NOT NULL)
SET @SQLString = @SQLString + 'AND (SomeTable.SomeColumn = @WhereParam2) '
...
如有必要,可以使用相同的结构向语句添加联接
orderby
结构取决于它的复杂程度,以及您是否知道所有可能涉及的列。如果它相对简单,您可以将其写成如下的CASE
语句,或者将其分解为单个参数,就像我为WHERE
子句所建议的那样
ORDER BY
CASE WHEN CHARINDEX(@SortColumns, 'SortCol1') > 0 THEN SortCol1 ELSE NULL END,
CASE WHEN CHARINDEX(@SortColumns, 'SortCol2') > 0 THEN SortCol2 ELSE NULL END,
...
这里最简单的做法可能是在应用程序级别而不是数据库级别进行排序,但这可能与复杂的
orderby
子句的参数化一样不可行。?是否有错误?MS SQL 2008 Msg 4145,级别15,状态1,第4行的错误在“顺序”附近预期条件的上下文中指定了非布尔类型的表达式。步骤#5正确。此步骤仅用于此代码的演示目的。我与第6步无关。我明白了,非常感谢,我想还有其他方法来处理这个问题。看起来我必须写一个循环来处理这个问题。非常感谢