欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Mybatis下的SQL注入漏洞原理及防護方法解析

 更新時間:2022年11月22日 08:56:25   作者:2ha0yuk7on  
SQL 注入是發(fā)生在 Web 程序中數(shù)據(jù)庫層的安全漏洞,是網(wǎng)站存在最多也是最簡單的漏洞,在實際項目中,即使使用了 Mybatis 框架,但仍然有可能因為編碼人員安全意識不足而導致 SQL 注入問題,這篇文章主要介紹了Mybatis下的SQL注入漏洞原理及防護方法?,需要的朋友可以參考下

之前我一直認為 Mybatis 框架下已經(jīng)實現(xiàn)預編譯機制,很多東西都封裝好了,應該基本上不會再有 SQL 注入問題了。近期在滲透中發(fā)現(xiàn),在實際項目中,即使使用了 Mybatis 框架,但仍然有可能因為編碼人員安全意識不足而導致 SQL 注入問題。出現(xiàn)情況還真不少,因此有了這篇文章。

一、前言

之前我一直認為 Mybatis 框架下已經(jīng)實現(xiàn)預編譯機制,很多東西都封裝好了,應該基本上不會再有 SQL 注入問題了。近期在滲透中發(fā)現(xiàn),在實際項目中,即使使用了 Mybatis 框架,但仍然有可能因為編碼人員安全意識不足而導致 SQL 注入問題。出現(xiàn)情況還真不少,因此有了這篇文章。

二、SQL 注入漏洞原理

1、概述

SQL 注入(SQL Injection)是發(fā)生在 Web 程序中數(shù)據(jù)庫層的安全漏洞,是網(wǎng)站存在最多也是最簡單的漏洞。主要原因是程序?qū)τ脩糨斎霐?shù)據(jù)的合法性沒有判斷和處理,導致攻擊者可以在 Web 應用程序中事先定義好的 SQL 語句中添加額外的 SQL 語句,在管理員不知情的情況下實現(xiàn)非法操作,以此來實現(xiàn)欺騙數(shù)據(jù)庫服務器執(zhí)行非授權的任意查詢,從而進一步獲取到數(shù)據(jù)信息。

簡單地說,就是通過在用戶可控參數(shù)中注入 SQL 語法,破壞原有 SQL 結(jié)構(gòu),達到編寫程序時意料之外結(jié)果的攻擊行為。其成因可以歸結(jié)為如下原因造成的:

  • 程序編寫者在處理應用程序和數(shù)據(jù)庫交互時,使用字符串拼接的方式構(gòu)造 SQL 語句。
  • 且未對用戶可控參數(shù)進行足夠的過濾。

2、漏洞復現(xiàn)

下面使用DVWA靶場來進行演示,網(wǎng)站架構(gòu)為PHP,我們重點關注漏洞原理即可。

該頁面提供了一個簡單的查詢功能,可以根據(jù)前端輸入的用戶ID來查詢對應的用戶信息。如圖,輸入 1,返回了對應 admin 用戶的信息。

查看該頁面的源代碼:

<?php

if( isset( $_REQUEST[ 'Submit' ] ) ) {
    // Get input
    $id = $_REQUEST[ 'id' ];

    // Check database
    $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

    // Get results
    while( $row = mysqli_fetch_assoc( $result ) ) {
        // Get values
        $first = $row["first_name"];
        $last  = $row["last_name"];

        // Feedback for end user
        echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
    }

    mysqli_close($GLOBALS["___mysqli_ston"]);
}

?>

進行代碼審計可以發(fā)現(xiàn),程序?qū)⑶岸溯斎氲?id 參數(shù)未加任何處理,直接拼接在了 SQL 語句中,那么此時就導致了SQL注入漏洞。

若此時攻擊者輸入的用戶ID為 1' or 1='1,則程序拼接后執(zhí)行的 SQL 語句變成了:

SELECT first_name, last_name FROM users WHERE user_id = '1' or 1='1';

可見,攻擊者通過單引號 ' 閉合了數(shù)據(jù)庫查詢語句,并且在查詢條件之后構(gòu)造了“或 1=1”,即“或真”的邏輯,導致查詢出了全部用戶的數(shù)據(jù)。

如果攻擊者可以任意替代提交的字符串,就可以利用 SQL 注入漏洞改變原有 SQL 語句的含義,進而執(zhí)行任意 SQL 命令,入侵數(shù)據(jù)庫進行脫庫、刪庫,甚至通過數(shù)據(jù)庫提權獲取系統(tǒng)權限,造成不可估量的損失。(SQL注入的場景類型非常之多,攻擊手法、繞過姿勢也非常多,本文不作重點討論)

3、修復建議

一般來說,防御 SQL 注入的最佳方式就是使用預編譯語句(其他防御方法還有很多,本文不作重點討論),綁定變量。例如:

String sql = "SELECT * FROM user_table WHERE username = ?";
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, "zxd");
ResultSet results = pstmt.executeQuery();

使用預編譯的 SQL 語句,SQL 語句的語義不會發(fā)生改變。在 SQL 語句中,變量用占位符 ? 表示,攻擊者無法改變 SQL 的結(jié)構(gòu)。

三、Mybatis 框架簡介

1、參數(shù)符號的兩種方式

Mybatis 的 SQL 語句可以基于注解的方式寫在類方法上面,更多的是以 xml 的方式寫到 xml 文件。Mybatis 中 SQL 語句需要我們自己手動編寫或者用 generator 自動生成。編寫 xml 文件時,MyBatis 支持兩種參數(shù)符號,#{}${} 。

  • #{} 使用預編譯,通過 PreparedStatement 和占位符來實現(xiàn),會把參數(shù)部分用一個占位符 ? 替代,而后注入的參數(shù)將不會再進行 SQL 編譯,而是當作字符串處理。可以有效避免 SQL 注入漏洞
  • ${} 表示使用拼接字符串,將接受到參數(shù)的內(nèi)容不加任何修飾符拼接在 SQL 中。易導致 SQL 注入漏洞。

兩者的區(qū)別如下:

  • #{} 為參數(shù)占位符 ?,即 SQL 預編譯。${} 為字符串替換,即 SQL 拼接。
  • #{} 是“動態(tài)解析->預編譯->執(zhí)行”的過程。${} 是“動態(tài)解析->編譯->執(zhí)行”的過程。
  • #{} 的變量替換是在 DBMS 中。${} 的變量替換是在 DBMS 外。
  • 變量替換后,#{} 對應的變量自動加上引號。變量替換后,${} 對應的變量不會加上引號。

2、漏洞復現(xiàn)

下面以一個查詢場景進行簡單演示,數(shù)據(jù)庫表 user_table 的表數(shù)據(jù)如下:

若沒有采用 JDBC 的預編譯模式,查詢 SQL 寫為:

<select id="getUser" parameterType="java.lang.String" resultType="user.NewUserDO">
    select * from user_table where username = '${username}'
</select>

這種寫法就產(chǎn)生了 SQL 語句的動態(tài)拼接,這樣格式的參數(shù)會直接參與 SQL 語句的編譯,從而不能避免SQL注入攻擊。

若此時攻擊者提交的參數(shù)值為 zxd' or 1='1,如下圖,利用 SQL 注入漏洞,成功查詢了所有用戶數(shù)據(jù)。

因此,應用 Mybatis 框架 SQL語句的安全寫法(即 JDBC 預編譯模式):

<select id="getUser" parameterType="java.lang.String" resultType="user.NewUserDO">    select * from user_table where username = #{username}</select>

可見,此時采用 JDBC 預編譯模式,即使攻擊者嘗試 SQL 注入攻擊,也只會將參數(shù)整體作為字符串處理,有效避免了 SQL 注入問題。

四、Mybatis 框架下的 SQL 注入問題及防護方法

還是以上節(jié)的查詢場景舉例,Mybatis 框架下易產(chǎn)生 SQL 注入漏洞的情況主要有以下三種:

1、模糊查詢

在模糊查詢場景下,考慮安全編碼規(guī)范,使用 #{} 傳入?yún)?shù):

<select id="getUser" parameterType="java.lang.String" resultType="user.NewUserDO">
    select * from user_table where username = #{username}
</select>

在這種情況下使用 #{} 程序會報錯:

于是很多安全經(jīng)驗不足的程序員就把 #{} 號改成了 ${},如果應用層代碼沒有對用戶輸入的內(nèi)容做處理勢必會產(chǎn)生SQL注入漏洞。

<select id="getUser" parameterType="java.lang.String" resultType="user.NewUserDO">
	select * from user_table where username like '%${username}%'
</select>

若此時攻擊者提交的參數(shù)值為 zxd' or 1=1#,如下圖,利用 SQL 注入漏洞,成功查詢了所有用戶數(shù)據(jù)。

因此,安全的寫法應當使用 CONCAT 函數(shù)連接通配符:

<select id="getUser" parameterType="java.lang.String" resultType="user.NewUserDO">
	select * from user_table where username like concat('%',#{username},'%')
</select>

2、帶有 IN 謂詞的查詢

在 IN 關鍵字之后使用 #{} 查詢多個參數(shù):

<select id="getUser" parameterType="java.lang.String" resultType="user.NewUserDO">
	select * from user_table where username in (#{usernames})
</select>

正常提交查詢參數(shù) 'zxd','hhh',因為預編譯機制,系統(tǒng)將我們輸入的字符當作了一個字符串,因此查詢結(jié)果為空,不能滿足業(yè)務功能需求。

于是很多安全經(jīng)驗不足的程序員就把 #{} 號改成了 ${}

<select id="getUser" parameterType="java.lang.String" resultType="user.NewUserDO">
	select * from user_table where username in (${usernames})
</select>

攻擊者提交參數(shù)值 'hhh') or 1=1#,利用 SQL 注入漏洞,成功查詢了所有用戶數(shù)據(jù)。

因此,此種情況下,安全的做法應當使用 foreach 標簽:

<select id="getUserFromList" resultType="user.NewUserDO">
	select * from user_table where username in
		<foreach collection="list" item="username" open="(" separator="," close=")">
			#{username}
		</foreach>
</select>

3、帶有動態(tài)排序功能的查詢

動態(tài)排序功能,需要在 ORDER BY 之后傳入?yún)?shù),考慮安全編碼規(guī)范,使用 #{} 傳入?yún)?shù):

<select id="getUserOrder" parameterType="java.lang.String" resultType="user.NewUserDO">
	select * from user_table order by #{column} limit 0,1
</select>

提交參數(shù) username 根據(jù)用戶名字段排序。但因為預編譯機制,系統(tǒng)將我們輸入的字符當作了一個字符串,根據(jù)字符串排序是不生效的,不能滿足業(yè)務功能需求。(根據(jù)用戶名字段排序,此時正常應返回 root 用戶)

于是很多安全經(jīng)驗不足的程序員就把 #{} 號改成了 ${}

<select id="getUserOrder" parameterType="java.lang.String" resultType="user.NewUserDO">
	select * from user_table order by ${column} limit 0,1
</select>

攻擊者提交參數(shù)值 username#,利用 SQL 注入漏洞,成功查詢了所有用戶數(shù)據(jù)。

因此,此種情況下,安全的做法應當在 Java 代碼層面來進行解決。可以設置一個字段值的白名單,僅允許用戶傳入白名單內(nèi)的字段。

String sort = request.getParameter("sort");
String[] sortWhiteList = {"id", "username", "password"};
if(!Arrays.asList(sortWhiteList).contains(sort)){
    sort = "id";
} 

或者僅允許用戶傳入索引值,代碼再將索引值映射成對應字段。

String sort = request.getParameter("sort");
switch(sort){
    case "1":
        sort = "id";
        break;
    case "2":
        sort = "username";
        break;
    case "3":
        sort = "password";
        break;
    default:
        sort = "id";
        break;
} 

需要注意的是在 mybatis-generator 自動生成的 SQL 語句中,ORDER BY 使用的也是 ${},而 LIKE 和 IN 沒有問題。

到此這篇關于Mybatis下的SQL注入漏洞原理及防護方法的文章就介紹到這了,更多相關Mybatis SQL注入漏洞原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 如何從eureka獲取服務的ip和端口號進行Http的調(diào)用

    如何從eureka獲取服務的ip和端口號進行Http的調(diào)用

    這篇文章主要介紹了如何從eureka獲取服務的ip和端口號進行Http的調(diào)用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • servlet 解決亂碼問題

    servlet 解決亂碼問題

    這篇文章主要介紹了servlet 解決亂碼問題 ,需要的朋友可以參考下
    2015-04-04
  • spring cloud中啟動Eureka Server的方法

    spring cloud中啟動Eureka Server的方法

    本篇文章主要介紹了spring cloud中啟動Eureka Server的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • Java線程狀態(tài)及同步鎖的操作方法

    Java線程狀態(tài)及同步鎖的操作方法

    Java中的thread類自帶有線程的一些方法,這些方法可以讓線程睡眠,插隊,提高線程調(diào)度的優(yōu)先級等等,它們提供了改變線程狀態(tài)的操作手段,這篇文章主要介紹了Java線程狀態(tài)及同步鎖,需要的朋友可以參考下
    2021-11-11
  • 基于Mybatis的配置文件入門必看篇

    基于Mybatis的配置文件入門必看篇

    這篇文章主要介紹了Mybatis的配置文件入門,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • JAVA中常用的設計模式:單例模式,工廠模式,觀察者模式

    JAVA中常用的設計模式:單例模式,工廠模式,觀察者模式

    設計模式(Design pattern)代表了最佳的實踐,通常被有經(jīng)驗的面向?qū)ο蟮能浖_發(fā)人員所采用。設計模式是軟件開發(fā)人員在軟件開發(fā)過程中面臨的一般問題的解決方案。這些解決方案是眾多軟件開發(fā)人員經(jīng)過相當長的一段時間的試驗和錯誤總結(jié)出來的。
    2020-04-04
  • Spring 實現(xiàn)excel及pdf導出表格示例

    Spring 實現(xiàn)excel及pdf導出表格示例

    本篇文章主要介紹了Spring 實現(xiàn)excel及pdf導出表格示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-03-03
  • java 函數(shù)的重載和重寫實例代碼

    java 函數(shù)的重載和重寫實例代碼

    本文主要介紹Java 的重載和重寫,學習java的同學都知道Java的多態(tài)有多重要,這里給大家舉例說明函數(shù)的重載和重寫,希望能幫助有需要的小伙伴
    2016-07-07
  • springboot基于Redis發(fā)布訂閱集群下WebSocket的解決方案

    springboot基于Redis發(fā)布訂閱集群下WebSocket的解決方案

    這篇文章主要介紹了springboot基于Redis發(fā)布訂閱集群下WebSocket的解決方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-01-01
  • mybatis分頁絕對路徑寫法過程詳解

    mybatis分頁絕對路徑寫法過程詳解

    這篇文章主要介紹了mybatis分頁絕對路徑寫法過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-12-12

最新評論