2011-02-03 91 views

回答

54

基本上,當您執行SQLCommand使用SQLParameters,參數從不直接插入語句。而是調用一個名爲sp_executesql的系統存儲過程,並給定SQL字符串和參數數組。

當這樣使用時,參數被隔離並作爲數據處理,而不必從語句中解析出來(因此可能改變它),所以參數包含的內容永遠不會被「執行」。你會得到一個很大的錯誤,即參數值在某些方面是無效的。

+1

您還可以得到一個錯誤的嘗試使用變量的地方SQL(和TSQL在這種情況下)不支持變量。 IE:`FROM`子句,一個參數代表一個逗號分隔的列表在`IN`條款等 – 2011-02-03 22:07:18

+0

我不認爲這個答案。您可以使用SQLParameter類調用存儲過程,該類將params傳遞給過程,但不調用sp_executesql。連接的sql字符串中的參數值會發生什麼? – Ian 2017-09-06 15:21:29

9

「參數的集合,如SqlParameterCollection提供類型檢查和長度驗證如果使用參數集合,輸入被視爲文字值,SQL Server不把它當作可執行代碼。使用參數集合的另一個好處是可以執行類型和長度檢查,範圍之外的值會觸發異常,這是深度防禦的一個好例子。「

http://msdn.microsoft.com/en-us/library/ff648339.aspx

4

當使用參數化查詢時,攻擊面將被減少到使用參數。

請使用SqlParameters,但不要忘記溢出,下溢和未驗證的參數。例如,如果方法是「proc buy_book (@price money」),則惡意攻擊者會試圖欺騙應用程序以運行@price設置爲0.01,或試圖讓應用程序通過提交導致溢出的內容來執行某些有趣的操作。 SQL溢出往往不是有趣的(即它們只是導致的異常,你是不太可能能夠寫入相鄰的存儲器)

21

一個比較容易理解的,更普遍的答案是這樣的:

想象一下,一個動態的SQL查詢:

sqlQuery='SELECT * FROM custTable WHERE User=' + Username + ' AND Pass=' + password

一個簡單的SQL注入將只是把用戶名作爲' OR 1=1--

這將有效地使SQL查詢:

sqlQuery='SELECT * FROM custTable WHERE User='' OR 1=1-- ' AND PASS=' + password

這是說選擇所有的客戶,他們的用戶名是空白('')或1=1,這是一個布爾值,等同於真實的。然後它使用--來註釋掉其餘的查詢。因此,這將打印出整個客戶表,或讓您隨心所欲地做任何事情。

現在,參數化查詢,採取不同的方式,用這樣的代碼:

sqlQuery='SELECT * FROM custTable WHERE User=? AND Pass=?' parameters.add("User", username) parameters.add("Pass", password)

其中用戶名和密碼是指向相關inputed用戶名和密碼的變量。

現在,在這一點上,你可能會認爲,這不會改變任何事情。當然,你仍然可以只投入了用戶名字段像沒有人OR 1 = 1' - ,有效地使查詢:

sqlQuery='SELECT * FROM custTable WHERE User=Nobody OR 1=1'-- AND Pass=?'

這似乎是一個有效的論據。但是,你會錯的。

方式參數化查詢工作,是SQL查詢作爲一個查詢發送,並且數據庫確切地知道這個查詢會做,然後纔將其輸入用戶名和密碼僅僅作爲值。這意味着它們不會影響查詢,因爲數據庫已經知道查詢將執行什麼操作。所以在這種情況下,它會尋找一個用戶名Nobody OR 1=1'--和一個空白的密碼,這應該是錯誤的。

雖然這不是一個完整的解決方案,並且輸入驗證仍然需要完成,因爲這不會影響其他問題,如攻擊,因爲您仍然可以將JavaScript放入數據庫。然後,如果這是讀出到一個頁面上,它會顯示爲正常的JavaScript,這取決於任何輸出驗證。所以最好的做法仍然是使用輸入驗證,但使用參數化查詢或存儲過程來阻止任何SQL攻擊。

來源:http://www.lavamunky.com/2011/11/why-parameterized-queries-stop-sql.html