Mybatis如何防止SQL注入

Mybatis如何防止SQL注入

什么是SQL注入

sql注入是一種代碼注入技術,將惡意的sql插入到被執(zhí)行的字段中,以不正當?shù)氖侄味鄶?shù)據(jù)庫信息進行操作。

在項目開發(fā)當中使用的用戶一般都是以root用戶進行使用而沒有

例如
一條普通的查詢SQL

select name from user where id = 1;

SQL注入的SQL

select name from user where id = 1;drop table user;

MySQL防止SQL注入

MySQL中的實現(xiàn)方案

預編譯 - 使用占位符

           Connection conn = getConn();//獲得連接
           String sql = "select name from user where id= ?";
           PreparedStatement pstmt = conn.prepareStatement(sql);
           pstmt.setString(1, userId);
           ResultSet rs=pstmt.executeUpdate();
           ......

? 代表的就是占位符

實現(xiàn)原理

為什么上面的代碼就不存在SQL注入了呢?因為使用了預編譯語句,預編譯語句在執(zhí)行時會把"select name from user where id= ?"語句事先編譯好,這樣當執(zhí)行時僅僅需要用傳入的參數(shù)替換掉占位符即可。<u>也就是不會傳入drop table user</u> ,只保證傳入?yún)?shù)而不傳入SQL。

存儲過程

存儲過程(Stored Procedure)是一組完成特定功能的SQL語句集,經編譯后存儲在數(shù)據(jù)庫中,用戶通過調用存儲過程并給定參數(shù)(如果該存儲過程帶有參數(shù))就可以執(zhí)行它,也可以避免SQL注入攻擊

           Connection conn = getConn();
           // 調用存儲過程
           stmt = conn.prepareCall("{call name_from_user(?,?)}");  
           stmt.setInt(1,2);  
           stmt.registerOutParameter(2, Types.VARCHAR);  
           stmt.execute();  
           String name= stmt.getString(2); 

存儲過程的實現(xiàn)

use user;
delimiter //
create  procedure name_from_user(in user_id int,out user_name varchar(20))
begin
    select name into user_name from user where id=user_id;
end
//
delimiter ;

字符處理

使用后端做字符處理(PS:如果是使用前端做處理的話,黑客可以越過前端傳入?yún)?shù));

利用字符串處理傳入的參數(shù)

權限設置

上述的三種處理辦法實質上都是對參數(shù)進行處理,權限設置的話就是對用戶設置最小權限粒度。

  1. 創(chuàng)建用戶 - create user

  2. 修改用戶權限 - GRANT privileges

    常用的權限

    • 表數(shù)據(jù): select, update, delete, insert
    • 表結構: create, alert, drop
    • 外鍵: references
    • 創(chuàng)建臨時表: create temporary tables
    • 操作索引: index
    • 視圖: create view, show view
    • 存儲過程: create routine, alert routine, execute
    • 所有權限: all

在連接數(shù)據(jù)庫的時候不使用root用戶,而是創(chuàng)建其他的用戶,根據(jù)業(yè)務來賦予不同的權限,但是對于DDL不對其他用戶進行賦予操作。

MyBatis如何實現(xiàn)的SQL注入

<select id="getNameByUserId" resultType="String">
        SELECT name FROM user where id = #{userId}
</select>

對應的java文件為:

public interface UserMapper{
   String getNameByUserId(@Param("userId") String userId);
}

可以看到輸入的參數(shù)是String類型的userId,當我們傳入userId="34;drop table user;"后,打印的語句(Mybatis日志)是這樣的:

select name from user where id = ?

不管輸入何種userID,他的sql語句都是這樣的。這就得益于mybatis在底層實現(xiàn)時使用預編譯語句。數(shù)據(jù)庫在執(zhí)行該語句時,直接使用預編譯的語句,然后用傳入的userId替換占位符?就去運行了。不存在先替換占位符?再進行編譯的過程,因此SQL注入也就沒有了生存的余地了。

那么mybatis是如何做到sql預編譯的呢?其實框架底層使用的正是PreparedStatement類。PreparedStaement類不但能夠避免SQL注入,因為已經預編譯,當N次執(zhí)行同一條sql語句時,節(jié)約了(N-1)次的編譯時間,從而能夠提高效率。

如果將上面的語句改成:

<select id="getNameByUserId" resultType="String">
        SELECT name FROM user where id = ${userId}
</select>

當我們輸入userId="34;drop table user;"后,打印的語句是這樣的:

select name from user where id = 34;drop table user;

此時,mybatis沒有使用預編譯語句,它會先進行字符串拼接再執(zhí)行編譯,這個過程正是SQL注入生效的過程。
因此在編寫mybatis的映射語句時,盡量采用“#{xxx}”這樣的格式。若不得不使用“${xxx}”這樣的參數(shù),要手工地做好過濾工作,來防止sql注入攻擊。

參考博客: https://blog.csdn.net/yizhenn/article/details/52384601?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 1.【底層實現(xiàn)原理】MyBatis是如何做到SQL預編譯的呢?其實在框架底層,是JDBC中的PreparedSta...
    南風nanfeng閱讀 2,238評論 0 0
  • 本文轉載自:https://blog.csdn.net/yizhenn/article/details/52384...
    _晴雨天閱讀 298評論 0 0
  • 1. 簡介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存儲過程以及高級映射的優(yōu)秀的...
    笨鳥慢飛閱讀 6,280評論 0 4
  • SQL注入 概念 危害 原理 實例 防御 基礎 - ### SQL語句所用符號不同數(shù)據(jù)庫的sql注入與提權常見S...
    yddchsc君閱讀 1,513評論 1 10
  • Web安全簡史 在Web1.0時代,人們更多是關注服務器端動態(tài)腳本語言的安全問題,比如將一個可執(zhí)行腳本(俗稱Web...
    潘良虎閱讀 4,038評論 3 72

友情鏈接更多精彩內容