SQL反模式學習筆記21 SQL注入
- 2019 年 10 月 4 日
- 筆記
目標:編寫SQL動態查詢,防止SQL注入
通常所說的「SQL動態查詢」是指將程式中的變數和基本SQL語句拼接成一個完整的查詢語句。
反模式:將未經驗證的輸入作為程式碼執行
當向SQL查詢的字元串中插入別的內容,而這些被插入的內容以你不希望的方式修改了查詢語法時,SQL注入就成功了。
傳統的SQL注入案例中,所插入的內容首先完成了一個查詢,然後再執行第二個完整的查詢邏輯比如:@bugId的值是
1234;Delete from Bugs,最後的SQL語句變成如下格式:
Select * from Bugs where bugId = 1234;Delete from Bugs
1、意外無處不在
由於字元串引起的語法錯誤,SQL語句是不會被執行的。
風險較大的是產生的SQL沒有任何語法錯誤,並且以一種你所不希望的方式執行。
2、對Web安全的嚴重威脅
當攻擊者能夠使用SQL注入操控你的SQL查詢語句時,就變成了一個巨大的威脅。
通常做法是在參數後插入額外的字元串,改變對應SQL語句的意義,例如:
Update Account
set password = SHA2('zyxzy'
where accountId = 123 or true –在傳入accountId參數等於123的後面,添加了 or true
理解SQL注入的關鍵,也是如何防止SQL注入的關鍵:SQL注入是通過在SQL語句被資料庫解析之前,
以修改其語法的形式工作的。只要在解析語句之前插入動態部分,就存在SQL注入的風險。
3、尋找解決方法
(1)轉義:對傳入的參數字元串進行轉義操作,使它們不至於成為字元串的結束符。
使用2個連續的單引號或者反斜杠來轉義。實現原理是在將應用程式中的數據插入到SQL語句之前
就進行轉換。這種技術能減少由於動態內容中不匹配是引號做造成的SQL注入的風險,但在非字元串
內容的情況下,這種技術就會失效。
(2)查詢參數:查詢參數的做法是在準備查詢語句的時候,在對應參數的地方使用「參數佔位符」。隨後,
在執行這個預先準備好的查詢時提供一個參數。
該方法的確是應對SQL注入的強勁解決方案,但是這還不是一個通用的解決方案,因為查詢參數總是被視為是一個字面值。
(a)多個值的列表不可以當成單一參數;
(b)表名無法作為參數;
(c)列名無法作為參數;
(d)SQL關鍵字無法作為參數;
(3)存儲過程:存儲過程是包含固定的SQL語句,這些語句在定義這個存儲過程的時候被解析的。
在存儲過程也可以使用SQL動態查詢的,這樣也存在安全隱患。
(4)數據訪問框架ORM:對於所有允許你使用字元串方式傳入SQL語句的框架來說,都無法抵禦SQL注入的攻擊。
如何識別反模式:幾乎所有的資料庫應用程式都動態地構建SQL語句,如果使用拼接字元串的形式或者將變數插入到字元串的
方法來構建SQL語句,這樣的sql語句就會受到SQL注入攻擊的威脅。
合理使用反模式:沒有任何理由使用反模式
解決方案:
1、過濾輸入內容,將所有不合法的字元從用戶輸入中剔除掉。
2、參數化動態內容:如果查詢中的變化部分是一些簡單的類型,應該使用查詢參數將其和SQL表達式分離。
如果是在RDBMS解析完SQL語句之後才插入這個參數值,沒有哪種SQL注入的功能能改變一個參數化了查詢的語法結構。
即使攻擊者嘗試使用帶有惡意的參數值,諸如123 or true ,關係型資料庫管理系統也會將這個字元串當成一個完整的值插入
Update Account
set password = SHA2('zyxzy'
where accountId ='123 or true' –當做一個完整的字元串而不會造成威脅
3、給動態輸入的值加引號
參數查詢通常來說是最好的解決方案,但是在有些特殊的情況下,參數的佔位符會導致查詢優化器無法選擇使用
哪個索引來進行優化查詢。
4、找個可靠的人來幫你審查SQL語句
在檢查程式碼是否包含SQL注入風險的時候,參考一下幾點:
(1)找出所有使用了程式變數、字元串鏈接或者替換等方法組成的SQL語句。
(2)跟蹤在SQL語句中使用的動態內容的來源。找出所有的外部輸入,比如用戶輸入、文件、系統環境、網路服務、
第三方程式碼,甚至於從資料庫中獲取的字元串。
(3)假設任何外部內容都是潛在的威脅,對於不受信任的內容都要進行過濾、驗證或者使用數組映射的方式來處理。
(4)在將外部數據合併到SQL語句時,使用查詢參數,或者用穩健的轉義函數預先處理。
(5)在存儲過程的程式碼以及任何其他使用SQL動態查詢語句的地方都做同樣的檢查。
結論:讓用戶輸入內容,但永遠別讓用戶輸入程式碼