1 什麼是 SQL 注入?
所謂 SQL 注入,便是指黑客將 SQL 代碼嵌入在輸入參數之中,在未經過濾的情況下直接拼接到 SQL 語句之中進行解析並執行的一種攻擊方法。
2 一個 SQL 注入的簡單例子
我們來模擬一個登錄場景,大家平時登錄網站什麼之類的需要啥呢?沒錯,賬號密碼!於是,我們的登錄界面一般都是這個樣子。。。
當我們輸入賬號密碼按下回車之後,會向後臺返回賬號密碼兩個參數。
https://mail.qq.com?username=3030&password=1010
然後在後臺相當於調用了下面的 SQL 語句:
SELECT * FROM user WHERE username = '3030' AND password = '1010'
好,上面老實人一般都會正常輸入賬號密碼,但總是有一些不法分子存在非分之想,他們會這麼輸入賬號密碼:
在後臺,執行的 SQL 語句變成了下面這條:
SELECT * FROM user WHERE username = '3030'#' AND password = '1010'
在 MySQL 中,# 之後的所有字符串都會被當成註釋進行處理,其實上面的 SQL 語句與下面這一條等價:
SELECT * FROM user WHERE username = '3030'
我們可以發現,只需要在賬號後面加上 '# 兩個字符,然後我們便可以隨便輸入密碼,因爲最終會被註釋掉。在這種情況下,我們只需要知道別人的賬號,即可不需要密碼進行登錄操作,這是一個非常嚴重的安全問題!
3 SQL 注入的條件
經過一個例子,我們來總結一下 SQL 注入的產生條件:
- 存在參數傳遞
- 參數值帶入 SQL 語句查詢並且執行
4 如何防止 SQL 注入攻擊?
在上面的例子中我們可以發現,SQL 注入攻擊實在太可怕了!那麼,我們又該如何防止 SQL 注入攻擊呢?一般我們可以採取以下方法:
- 對輸入變量的類型與格式進行檢查。如果參數類型爲整數,則加上必要的判斷;如果參數類型爲字符串,則使用正則表達式進行過濾操作(賬號必須爲 [0-9a-zA-Z] 範圍內的字符串)
- 對特殊字符進行過濾和轉義。例如對 ’ 或 " 或 \ 等特殊字符進行轉義
- 使用 MySQL 的預編譯機制
什麼是預編譯?
一般 SQL 語句的執行可以分爲以下三個過程:
- 詞法和語義解析
- 優化 SQL 語句,制定執行計劃
- 執行並返回結果
這種是一般情況,但是我們在某些場景下可能存在 SQL 語句反覆執行或者每次執行只有個別值不同的情況,如果每次執行都要重新經過上面三個步驟,顯然效率是非常不可觀的,幸好預編譯機制可以有效解決這個問題。
預編譯機制將 SQL 語句中的值用佔位符替代,可以理解爲將 SQL 語句模板化或者參數化。使用預編譯,我們便可以一次編譯、多次運行,省去了解析,優化等過程,另外使用預編譯機制也可以有效防止 SQL 注入。
問題來了,爲什麼預編譯機制可以防止 SQL 注入呢?使用預編譯機制,我們後臺的 SQL 語句就可以抽象爲:
SELECT * FROM user WHERE username = ? AND password = ?
在該語句中,無論用戶輸入何種賬號密碼,邏輯關係始終爲 AND,不會導致 SQL 語句結構發生變化。參數值是參數值,語句是語句,參數的值並不是語句的一部分,MySQL 只按語句的語義來執行 SQL。
5 Mybatis 如何防止 SQL 注入?
MyBatis 是我們常用的持久層框架,其 SQL 均需要我們手動編寫,那麼它又是如何防止 SQL 注入的呢?
在編寫映射語句時,使用 #{} 會進行預編譯處理,其 SQL 語句類似於下面的格式:
SELECT * FROM user WHERE username = ? AND password = ?
SQL 執行時,會直接將佔位符 ?替換爲參數,自然不會存在 SQL 注入的問題。