SQL注入及防止注入措施
1、Sql注入是怎麼產生的?
- WEB開發人員無法保證所有的輸入都已經過濾
- 攻擊者利用傳送給SQL伺服器的輸入資料構造可執行的SQL程式碼
- 資料庫未做相應的安全配置
2、如何尋找Sql注入?
- 識別web應用中的所有輸入點
- 瞭解哪些型別的請求會出發異常
- 檢測伺服器響應中的異常
3、如何進行SQL注入攻擊?
- 數字注入
比如:用or 前一個條件不匹配後一個條件完全匹配。比如id = -1 or 1 = 1 - 字串注入
比如:用 ‘ 閉合查詢,然後後面新增#,用來將後面的語句註釋掉
4、如何預防SQL注入?
- 嚴格檢查輸入變數的型別和格式
- 過濾和轉義特殊字元
- 利用mysql的預編譯機制
5、預編譯的相關知識
sql注入只對sql語句的準備(編譯)過程有破壞作用,而PreparedStatement已經準備(編譯)好了,執行階段只是把輸入串作為資料處理,而不再對sql語句進行解析、準備(編譯),因此也就避免了sql注入問題。
- 什麼是預編譯語句
預編譯語句PreparedStatement 是java.sql中的一個介面,它是Statement的子介面。通過Statement物件執行SQL語句時,需要將SQL語句傳送給DBMS,由DBMS首先進行編譯後再執行。預編譯語句和Statement不同,在建立PreparedStatement 物件時就指定了SQL語句,該語句立即傳送給DBMS進行編譯。當該編譯語句被執行時,DBMS直接執行編譯後的SQL語句,而不需要像其他SQL語句那樣首先將其編譯。 - 什麼時候使用預編譯語句
一般是在需要反覆使用一個SQL語句時才使用預編譯語句,預編譯語句常常放在一個fo r或者while迴圈裡面使用,通過反覆設定引數從而多次使用該SQL語句。為了防止SQL注入漏洞,在某些資料操作中也使用預編譯語句。 - 為什麼使用預編譯語句
預編譯機制除了在開篇提到的可以防止SQL注入外,還有一下兩方面的優點:
a、提高效率:資料庫處理一個SQL語句,需要完成解析SQL語句、檢查語法和語義以及生成程式碼,一般說來,處理時間要比執行語句所需要的時間長。預編譯語句在建立的時候已經是將指定的SQL語句傳送給了DBMS,完成了解析、檢查、編譯等工作。因此,當一個SQL語句需要執行多次時,使用預編譯語句可以減少處理時間,提高執行效率。
b、提高程式碼的可讀性和可維護性
6、防止SQL注入以及預編譯機制在mybatis中的應用
‘#’ 與 ‘$’區別
動態 SQL是 mybatis 的強大特性之一,也是它優於其他 ORM 框架的一個重要原因。mybatis 在對 sql 語句進行預編譯之前,會對 sql 進行動態解析,解析為一個 BoundSql 物件,也是在此處對動態 SQL 進行處理的。
在動態 SQL 解析階段,#{ } 和 ${ } 會有不同的表現:
#{} 解析為一個 JDBC 預編譯語句(prepared statement)的引數標記符。
例如,sqlMap 中如下的 sql 語句
select * from user where name = #{name};
解析為:
select * from user where name = ?;
一個 #{ } 被解析為一個引數佔位符 ? 。
而,${ } 僅僅為一個純碎的 string 替換,在動態 SQL 解析階段將會進行變數替換
例如,sqlMap 中如下的 sql
select * from user where name = ${name};
當我們傳遞的引數為 “ruhua” 時,上述 sql 的解析為:
select * from user where name = "ruhua";
預編譯之前的 SQL 語句已經不包含變數 name 了。
綜上所得, ${ } 的變數的替換階段是在動態 SQL 解析階段,而 #{ }的變數的替換是在 DBMS 中。
7、mybatis中‘#’ 與 ‘$’的用法
能使用 #{ } 的地方就用 #{ }
首先這是為了效能考慮的,相同的預編譯 sql 可以重複利用。
其次, ${ } 在預編譯之前已經被變數替換了,這會存在 sql 注入問題 。例如,如下的 sql,
select * from ${tableName} where name = #{name}
假如,我們的引數 tableName 為 user; delete user; – ,那麼 SQL 動態解析階段之後,預編譯之前的 sql 將變為
select * from user; delete user; -- where name = ?;
– 之後的語句將作為註釋,不起作用,因此本來的一條查詢語句偷偷的包含了一個刪除表資料的 SQL!
2、表名作為變數時,必須使用 ${ }
這是因為,表名是字串,使用 sql 佔位符替換字串時會帶上單引號 ” ,這會導致 sql 語法錯誤,例如:
select * from #{tableName} where name = #{name};
預編譯之後的sql 變為:
select * from ? where name = ?;
假設我們傳入的引數為 tableName = “user” , name = “ruhua”,那麼在佔位符進行變數替換後,sql 語句變為
select * from 'user' where name='ruhua';
上述 sql 語句是存在語法錯誤的,表名不能加單引號 ” (注意,反引號 “是可以的)。
8、mybatis sql 動態解析
mybatis 在呼叫 connection 進行 sql 預編譯之前,會對sql語句進行動態解析,動態解析主要包含如下的功能:
* 佔位符的處理
* 動態sql的處理
* 引數型別校驗