主要原因(不使用組字串方式執行SQL)
像上述這樣丟進SQL Server的參數是不會被當作 SQL 語法去執行的,因此就算使用者輸入的參數有注入的語法也不會因此執行成功!
在使用參數化查詢語法的情況下,SQL Server會先將 SQL 語句進行編譯,之後再把使用者輸入的參數丟進先前編譯的 SQL 語句再次執行。而預處理的 SQL 語句除了防範 SQL injection 更提升了效能。
接著將來看看使用不同的查詢在SQL Server Execution Plan上的差異!
如何觀看Execution Plan上的差異
首先,我們要了解SQL Server收到一個指令後會做些什麼事情:
實際上可能有些差異,但大致的步驟如下,
SQL Server收到SQL指令 --> 進行語法解析、語意分析 --> 編譯SQL生成執行計劃 -->選擇執行計劃 -->執行執行計劃。
接著我們就來創建一張表並實際來看看以下三種查詢在SQL Server是怎麼被執行的:
(1) 正常的查詢,執行有漏洞的SP
(2) SQL Injection查詢,執行有漏洞的SP
(3) 參數化查詢,執行使用參數化寫法的SP
首先創建一張USERS表,語法如下:
並且寫入一些測試資料,語法如下:
執行完上述語法後,此時資料庫內應會有這五筆資料:
接下來分別測試三種查詢方式,並觀察其Execution Plan,此處將使用Store Procedure做示範:
首先,分別建立兩個Store Procedure
WrongSP (使用組字串的方式最後使用EXEC執行)
CorrectSP (使用參數化查詢方式)
(1) 正常的查詢,執行有漏洞的SP
(2) SQL Injection查詢,執行有漏洞的SP
(3) 參數化查詢,執行使用參數化寫法的SP
若不清楚物件類型的區別這邊幫大家擷取Microsoft的文件,該欄位內容如下:
以上試驗應該可以看出三種查詢其在執行Execution Plan上是有差異的,
(1) 正常的查詢:執行三次WrongSP,執行計畫結果為 → 使用3次Proc,另外使用2次Adhoc,我再舉一個例子可以更明顯看出原因,
一樣都是執行三次WrongSP,我只改變了查詢條件的一個字便使用了三個不同的Execution Plan,表示三次查詢皆沒有重用Proc的Execution Plan!
(2) SQL Injection查詢:執行三次WrongSP,執行計畫結果為 → 使用3次Proc,另外使用2次Adhoc,會有這樣的結果在剛剛第一點的例子也解釋了這是因為沒有重用Proc的Execution Plan!
(3) 參數化查詢:執行三次CorrectSP,執行計畫結果為 → 使用3次Proc,這表示了什麼?就是Proc的Execution Plan被重用了!
經過上述說明,可以看到在第二個例子(SQL Injection查詢)中,SQL表示的含義是找出(UserName='' 且 CellPhoneNumber='') 或者1=1 的所有User,這段SQL Injection語法改變了原來自己的初衷,也就是SQL的語意發生了改變,而為什麼發生了改變呢?原因是沒有重用先前建立好的Execution Plan(Proc),造成SQL Server對注入後的SQL語法重新進行了編譯、生成Execution Plan並執行新的Execution Plan。
結語
參數化查詢爲什麼能防止SQL Injection,主要是因為不使用「組字串」的方式來執行 SQL。而在第二部分觀看Execution Plan上的差異,可以得知執行計畫未被更改(也就是重用Execution Plan),是可以防止SQL Injection的。
而Insert/Update/Delete也是一樣的道理,只要可以重用Execution Plan,SQL所要表達的語意就不會變化!
謝謝你的閱讀!如果有任何回饋或疑問,歡迎留言給我!
如果對我的文章有興趣,請不吝按下Follow & Clap!
每個月都會認真更新文章唷😊 千萬別錯過了~