Best-Practices

傳遞和使用參數的最佳實踐安全/性能

  • September 16, 2015

我們的高級程序員一直讓我編寫以下格式的儲存過程以防止注入攻擊。他說最好的做法是接受參數,然後在正文中聲明一個新變數並將該變數分配給參數,這一步是針對注入攻擊的額外保護,因為它強制任何注入嘗試被視為數據而不是被採取字面上地。真的嗎?我認為這會減慢查詢速度並使用額外的記憶體並且不會添加任何額外的保護,但我可能是錯的。下面的例子。

   CREATE PROCEDURE [dbo].[sp_foo_GET] 
       @parAcct            NVARCHAR(20)
AS
BEGIN
   SET NOCOUNT ON;
   DECLARE 
       @varAcct            NVARCHAR(20) = @parAcct;

   SELECT [userid] 
   FROM [tblAccounts] 
   WHERE [accountID] = @varAcct;   
END

編輯 在與程序員交談後,他似乎認為將參數傳遞給一個變數並將它們分配給聲明的變數有助於提高安全性,並且會導致查詢執行得更快。

他似乎很困惑。從局部變數中使用相同的值應該與從輸入參數中使用它沒有什麼不同。您的同事在使用參數化查詢(有時稱為準備好的語句)而不是完整的即席 SQL 方面是否走錯了路?

例如:

resultSet = dbconnector.getRS('EXEC sp_foo_GET \''+inputVariable+'\');

可能是注入路徑,並且在過程內的變數之間移動值根本不會影響它,因為註入的程式碼不會被過程看到。如果inputVariable有值xxx'; WAITFOR DELAY '00:10:00'--發送到伺服器的 SQL 將是

EXEC sp_foo_GET 'xxx'; WAITFOR DELAY '00:10:00'--'

您的過程將在輸入參數設置為的情況下執行,xxx並且根本不知道額外的程式碼,它在過程呼叫完成後執行。

使用準備好的語句,假設您的數據庫訪問庫正確支持它們並且沒有在幕後做臨時愚蠢,這不會發生:

resultSet = dbconnector.getRSWithParams('EXEC sp_foo_GET ?', [inputVariable]);

您的過程將使用該值xxx'; WAITFOR DELAY '00:10:00'--而不是被視為要執行的額外程式碼來呼叫。

當然,該技術可能是他希望你遵循的更大模式的一部分,當你做更高級的事情時,其目的會變得清晰,但實際上並沒有什麼用處(除了讓你養成遵循模式的習慣)階段,但我懷疑他只是誤解,因此增加了不必要的工作。你能請他更詳細地解釋一下嗎?也許他可以為您提供一個他認為該模式可以防止的範例呼叫?

評論後重新。表現

根據您的評論,雖然我懷疑這種模式是否存在任何安全原因,但關於它可能會產生性能差異的新解釋更有效,儘管您可能會發現在大多數情況下它沒有任何區別,並且在某些情況下它會降低而不是提高性能,所以建議進行基準測試,而不是盲目地使用該模式。

問題來自查詢計劃記憶體以及輸入參數和文字的處理方式與局部變數的不同。我不會在這裡詳細介紹它,因為我們偏離了原始問題(在 MS 文件和網路中搜尋一般圍繞片語“參數嗅探”、“查詢計劃記憶體”和“” OPTIMIZE FOR,然後問一個新問題,如果您在閱讀了一些內容後需要更清晰)但作為十人的初學者:在上面的範例中,您對局部變數所做的操作實際上與使用 聲明過程相同OPTION (OPTIMIZE FOR (@parAcct UNKNOWN))。這個的影響,與任何優化提示一樣,根據過程中正在執行的查詢以及它們所觸及的數據的平衡,可能會有很大差異。

在調試性能問題時,使用記憶體計劃的輸入參數、文字和局部變數之間的差異可能很大(如果您不知道,這可能意味著您在調試/測試時看到的性能配置文件與生產中看到的完全不同)問題)。http://www.brentozar.com/archive/2014/06/tuning-stored-procedures-local-variables-problems/涵蓋了這個特定背景下的問題。

引用自:https://dba.stackexchange.com/questions/115073