亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

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

一、前言

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

二、SQL 注入漏洞原理

1、概述

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

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

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

2、漏洞復(fù)現(xiàn)

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

該頁面提供了一個簡單的查詢功能,可以根據(jù)前端輸入的用戶ID來查詢對應(yīng)的用戶信息。如圖,輸入 1,返回了對應(yīng) 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"]);
}

?>

進(jìn)行代碼審計(jì)可以發(fā)現(xiàn),程序?qū)⑶岸溯斎氲?id 參數(shù)未加任何處理,直接拼接在了 SQL 語句中,那么此時就導(dǎo)致了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”,即“或真”的邏輯,導(dǎo)致查詢出了全部用戶的數(shù)據(jù)。

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

3、修復(fù)建議

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

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

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

三、Mybatis 框架簡介

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

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

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

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

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

2、漏洞復(fù)現(xiàn)

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

若沒有采用 JDBC 的預(yù)編譯模式,查詢 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ù)。

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

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

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

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

還是以上節(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>

在這種情況下使用 #{} 程序會報(bào)錯:

于是很多安全經(jīng)驗(yàn)不足的程序員就把 #{} 號改成了 ${},如果應(yī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ù)。

因此,安全的寫法應(yīng)當(dāng)使用 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 關(guān)鍵字之后使用 #{} 查詢多個參數(shù):

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

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

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

<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ù)。

因此,此種情況下,安全的做法應(yīng)當(dāng)使用 foreach 標(biāo)簽:

<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ù)用戶名字段排序。但因?yàn)轭A(yù)編譯機(jī)制,系統(tǒng)將我們輸入的字符當(dāng)作了一個字符串,根據(jù)字符串排序是不生效的,不能滿足業(yè)務(wù)功能需求。(根據(jù)用戶名字段排序,此時正常應(yīng)返回 root 用戶)

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

<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ù)。

因此,此種情況下,安全的做法應(yīng)當(dāng)在 Java 代碼層面來進(jìn)行解決??梢栽O(shè)置一個字段值的白名單,僅允許用戶傳入白名單內(nèi)的字段。

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

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

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 沒有問題。

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

相關(guān)文章

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

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

    這篇文章主要介紹了如何從eureka獲取服務(wù)的ip和端口號進(jìn)行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類自帶有線程的一些方法,這些方法可以讓線程睡眠,插隊(duì),提高線程調(diào)度的優(yōu)先級等等,它們提供了改變線程狀態(tài)的操作手段,這篇文章主要介紹了Java線程狀態(tài)及同步鎖,需要的朋友可以參考下
    2021-11-11
  • 基于Mybatis的配置文件入門必看篇

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

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

    JAVA中常用的設(shè)計(jì)模式:單例模式,工廠模式,觀察者模式

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

    Spring 實(shí)現(xiàn)excel及pdf導(dǎo)出表格示例

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

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

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

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

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

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

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

最新評論