2012-06-14 48 views
0

我想轉換SQL語句以支持sp_executesql使其安全,但我碰到了一個不安全的區域。希望你們能幫助我解決這個問題。我創建了臨時表以便更容易地演示問題。sp_executesql保護動態搜索關鍵字

問題在於步驟#6。我可以使用STEP#5,但這不安全並且容易被黑客入侵。由於系統性能的原因,我並不是真的想要關閉關鍵字並多次搜索。

MS SQL 2008錯誤消息4145,級別15,狀態1,行4在'ORDER'附近預期條件的上下文中指定的非布爾類型的表達式。

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 ('[email protected]+') ORDER BY '[email protected];--unsafe, open to hackers 
    EXECUTE sp_executesql @SQLString, @ParmDefinition, @Param1ProductName = @Keywords, @[email protected]; 

--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, @[email protected]; 

--Drop temp table 
DROP TABLE #TempTable 
+0

#6如何不工作?有錯誤嗎? –

+0

MS SQL 2008錯誤消息4145,級別15,狀態1,行4在'ORDER'附近預期條件的上下文中指定的非布爾類型的表達式。 –

回答

0

我認爲這個問題是,在第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 

取決於你有多複雜指望你的過濾器是,你也許可以在標準編寫到一個臨時表,並執行一個連接到臨時表來限制返回的結果數據。關於我的頭頂,我不確定如何最好地對結果數據進行排序,除非您在調用代碼中執行了這些操作?

+0

你是對的第5步。此步驟僅用於此代碼的演示目的。我和第六步沒有任何關係。 –

0

你的錯誤消息表明在步驟6中WHERE子句是無效的,所以是ORDER BY子句。這是因爲您將字符串作爲參數傳遞給sp_executesql並試圖將它們用作整個子句。此外,該聲明引用參數@SortColumns,但您似乎已命名參數@Param2SortColumns

有什麼一些SQL服務器的MVP已經寫了一讀:

http://www.sommarskog.se/dynamic_sql.html

更重要的一點:http://www.sommarskog.se/dyn-search.html

http://www.sqlmag.com/article/tsql3/parameterizing-result-order

我沒有看到一個簡單的方法來改變你的程序來完成這項工作,因爲你傳遞了整個WHEREORDER BY子句作爲參數。你應該做的是重新設計proc。將每個WHERE標準作爲個別參數提供給ups_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) ' 
    ... 

如果有必要,可以使用相同的結構來增加連接的語句。

ORDER BY結構取決於如何複雜,這可能得到,而你是否知道所有可能涉及的列。如果是比較簡單的,你可以按如下寫出來作爲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, 
    ... 

最簡單的事情,在這裏做可能是在應用程序級別,而不是數據庫進行排序,但可能是一樣不可行的複雜ORDER BY條款是參數化。

+0

我看到了,非常感謝,我認爲還有其他方法可以解決這個問題。它看起來像我必須編寫一個循環來處理這個問題。非常感謝 –