1、SQL注入漏洞基本原理
在常見的web漏洞中,SQL注入漏洞較爲常見,危害也較大。攻擊者一旦利用系統中存在的SQL注入漏洞來發起攻擊,在條件容許的狀況下,不只能夠獲取整站數據,還可經過進一步的滲透來獲取服務器權限,從而進入內網。
注入攻擊的本質,是把用戶輸入的數據當作代碼執行。這裏有兩個關鍵條件,第一個是用戶可以控制輸入;第二個是本來程序要執行的代碼,拼接了用戶輸入的數據。接下來講下SQL注入漏洞的原理。
舉個栗子。
當用戶發送GET請求:
http://www.xxx.com/news.jsp?id=1
這是一個新聞詳情頁面,會顯示出新聞的title和content,程序內部會接收這個id參數傳遞給SQL語句,SQL以下:
SELECT title,content FROM news WHERE id = 1
這是SQL的原義,也是程序員想要獲得的結果,可是若是用戶改變了id的內容,修改爲以下:
http://www.jd.com/news.jsp?id=1 and 1=2 UNION SELECT userna-me, password FROM admin
此時內部程序執行的SQL語句爲:
SELECT title,content FROM news WHERE id = 1 and 1=2 UNION SELECT username, password FROM admin
這條SQL的原義就會被改變,致使將管理員數據表中的用戶名顯示在頁面title位置,密碼顯示在頁面content位置,攻擊成功。
2、Mybatis框架介紹
1. Mybatis框架架構
Mybatis框架架構講解(架構圖以下圖所示):
(1)加載配置:配置來源於兩個地方,一處是配置文件,一處是Java代碼的註解,將SQL的配置信息加載成爲一個個MappedStatement對象(包括了傳入參數映射配置、執行的SQL語句、結果映射配置),存儲在內存中。
(2) SQL解析:當API接口層接收到調用請求時,會接收到傳入SQL的ID和傳入對象(能夠是Map、JavaBean或者基本數據類型),Mybatis會根據SQL的ID找到對應的MappedStatement,而後根據傳入參數對象對MappedStatement進行解析,解析後能夠獲得最終要執行的SQL語句和參數。
(3)SQL執行:將最終獲得的SQL和參數拿到數據庫進行執行,獲得操做數據庫的結果。
(4)結果映射:將操做數據庫的結果按照映射的配置進行轉換,能夠轉換成HashMap、JavaBean或者基本數據類型,並將最終結果返回。
Mybatis架構圖
2. JDBC預編譯模式
Mybatis框架做爲一款半自動化的持久層框架,其SQL語句都須要咱們本身手動編寫,此時就須要按照安全編碼規範進行開發,以防止SQL注入漏洞的產生。
針對上一節中所舉的例子,應用Mybatis框架SQL語句安全寫法(即JDBC預編譯模式)能夠寫爲:
select * from news where id=#{id},這種寫法能夠很好地避免SQL注入漏洞的產生。
3. 動態拼接SQL語句
若是在開發過程當中沒有采用JDBC的預編譯模式,如咱們將上述SQL語句寫爲:select * from news where id=${id},這種寫法就產生了SQL語句的動態拼接。由於」${xxx}」這樣格式的參數會直接參與SQL語句的編譯,從而不能避免SQL注入攻擊。
3、Mybatis框架下易產生SQL注入漏洞場景分析
在基於Mybatis框架的Java白盒代碼審計工做中,一般將着手點定位在Mybatis的配置文件中。經過查看這些與數據庫交互的配置文件來肯定SQL語句中是否存在拼接狀況,進而確立跟蹤點。經過總結,Mybatis框架下易產生SQL注入漏洞的狀況主要分爲如下三種:
1. 模糊查詢like
還以第一節中提到的新聞詳情頁面爲例,按照新聞標題對新聞進行模糊查詢,若是考慮安全編碼規範問題,其對應的SQL語句以下:
Select * from news where title like ‘%#{title}%’,
但因爲這樣寫程序會報錯,研發人員將SQL查詢語句修改以下:
Select * from news where title like ‘%${title}%’,
在這種狀況下咱們發現程序再也不報錯,可是此時產生了SQL語句拼接問題,若是java代碼層面沒有對用戶輸入的內容作處理勢必會產生SQL注入漏洞。
2. in以後的參數
在對新聞進行同條件多值查詢的時候,如當用戶輸入1001,1002,1003…100N時,若是考慮安全編碼規範問題,其對應的SQL語句以下:
Select * from news where id in (#{id}),
但因爲這樣寫程序會報錯,研發人員將SQL查詢語句修改以下:
Select * from news where id in (${id}),
修改SQL語句以後,程序中止報錯,可是卻引入了SQL語句拼接的問題,若是研發人員沒有對用戶輸入的內容作過濾,勢必會產生SQL注入漏洞。
3. order by以後
當根據發佈時間、點擊量等信息對新聞進行排序的時候,若是考慮安全編碼規範問題,其對應的SQL語句以下:
Select * from news where title =‘京東’ order by #{time} asc,
但因爲發佈時間time不是用戶輸入的參數,沒法使用預編譯。研發人員將SQL查詢語句修改以下:
Select * from news where title =‘京東’ order by ${time} asc,
修改以後,程序經過預編譯,可是產生了SQL語句拼接問題,極有可能引起SQL注入漏洞。
4、Mybatis框架下SQL注入漏洞修復建議1. 模糊查詢like SQL注入修復建議
按照新聞標題對新聞進行模糊查詢,可將SQL查詢語句設計以下:
select * from news where tile like concat(‘%’,#{title}, ‘%’),
採用預編譯機制,避免了SQL語句拼接的問題,從根源上防止了SQL注入漏洞的產生。
2. in以後的參數SQL注入修復建議
在對新聞進行同條件多值查詢的時候,可以使用Mybatis自帶循環指令解決SQL語句動態拼接的問題:
<select id="dynamicForeachTest" parameterType="java.util.List" resultType="Blog">
select * from t_blog where id in
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
3. order by SQL注入修復建議--在Java層面作映射
預編譯機制只能處理查詢參數,其餘地方還須要研發人員根據具體狀況來解決。如前面提到的排序情景: Select * from news where title =‘京東’ order by #{time} asc,這裏time不是查詢參數,沒法使用預編譯機制,只能這樣拼接:Select * from news where title =‘京東’ order by ${time} asc 。
針對這種狀況研發人員能夠在java層面作映射來進行解決。如當存在發佈時間time和點擊量click兩種排序選擇時,咱們能夠限制用戶只能輸入1和2。當用戶輸入1時,咱們在代碼層面將其映射爲time,當用戶輸入2時,將其映射爲click。而當用戶輸入1和2以外的其餘內容時,咱們能夠將其轉換爲默認排序選擇time(或者click)。