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

mybatis防止SQL注入的方法實(shí)例詳解

 更新時(shí)間:2018年04月28日 09:36:48   作者:bwh0520  
SQL注入是一種很簡(jiǎn)單的攻擊手段,但直到今天仍然十分常見(jiàn)。那么mybatis是如何防止SQL注入的呢?下面腳本之家小編給大家?guī)?lái)了實(shí)例代碼,需要的朋友參考下吧

SQL注入是一種很簡(jiǎn)單的攻擊手段,但直到今天仍然十分常見(jiàn)。究其原因不外乎:No patch for stupid。為什么這么說(shuō),下面就以JAVA為例進(jìn)行說(shuō)明:

假設(shè)數(shù)據(jù)庫(kù)中存在這樣的表:

table user( 
id varchar(20) PRIMARY KEY , 
name varchar(20) , 
age varchar(20) ); 

然后使用JDBC操作表:

private String getNameByUserId(String userId) { 
 Connection conn = getConn();//獲得連接 
String sql = "select name from user where id=" + userId; 
 PreparedStatement pstmt = conn.prepareStatement(sql); 
 ResultSet rs=pstmt.executeUpdate(); 
 ...... 
} 

上面的代碼經(jīng)常被一些開(kāi)發(fā)人員使用。想象這樣的情況,當(dāng)傳入的userId參數(shù)為"3;drop table user;"時(shí),執(zhí)行的sql語(yǔ)句如下:

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

數(shù)據(jù)庫(kù)在編譯執(zhí)行之后,刪除了user表。瞧,一個(gè)簡(jiǎn)單的SQL注入攻擊生效了!之所以這樣,是因?yàn)樯厦娴拇a沒(méi)有符合編程規(guī)范。

當(dāng)我們按照規(guī)范編程時(shí),SQL注入就不存在了。這也是避免SQL注入的第一種方式:預(yù)編譯語(yǔ)句,代碼如下:

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

為什么上面的代碼就不存在SQL注入了呢?因?yàn)槭褂昧祟A(yù)編譯語(yǔ)句,預(yù)編譯語(yǔ)句在執(zhí)行時(shí)會(huì)把"select name from user where id= ?"語(yǔ)句事先編譯好,這樣當(dāng)執(zhí)行時(shí)僅僅需要用傳入的參數(shù)替換掉?占位符即可。而對(duì)于第一種不符合規(guī)范的情況,程序會(huì)先生成sql語(yǔ)句,然后帶著用戶(hù)傳入的內(nèi)容去編譯,這恰恰是問(wèn)題所在。

除了使用預(yù)編譯語(yǔ)句之外,還有第二種避免SQL注入攻擊的方式:存儲(chǔ)過(guò)程。存儲(chǔ)過(guò)程(Stored Procedure)是一組完成特定功能的SQL語(yǔ)句集,經(jīng)編譯后存儲(chǔ)在數(shù)據(jù)庫(kù)中,用戶(hù)通過(guò)調(diào)用存儲(chǔ)過(guò)程并給定參數(shù)(如果該存儲(chǔ)過(guò)程帶有參數(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); 

上面的代碼中對(duì)應(yīng)的存儲(chǔ)過(guò)程如下:

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 ; 

當(dāng)然用戶(hù)也可以在前端做字符檢查,這也是一種避免SQL注入的方式:比如對(duì)于上面的userId參數(shù),用戶(hù)檢查到包含分號(hào)就提示錯(cuò)誤。

不過(guò),從最根本的原因看,SQL注入攻擊之所以存在,是因?yàn)閍pp在訪問(wèn)數(shù)據(jù)庫(kù)時(shí)沒(méi)有使用最小權(quán)限。想來(lái)也是,大家好像一直都在使用root賬號(hào)訪問(wèn)數(shù)據(jù)庫(kù)。

那么mybatis是如何避免sql注入攻擊的呢?還是以上面的表user為例:
假設(shè)mapper文件為:

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

對(duì)應(yīng)的java文件為:

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

可以看到輸入的參數(shù)是String類(lèi)型的userId,當(dāng)我們傳入userId="34;drop table user;"后,打印的語(yǔ)句是這樣的:

select name from user where id = ? 

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

那么mybatis是如何做到sql預(yù)編譯的呢?其實(shí)框架底層使用的正是PreparedStatement類(lèi)。PreparedStaement類(lèi)不但能夠避免SQL注入,因?yàn)橐呀?jīng)預(yù)編譯,當(dāng)N次執(zhí)行同一條sql語(yǔ)句時(shí),節(jié)約了(N-1)次的編譯時(shí)間,從而能夠提高效率。

如果將上面的語(yǔ)句改成:

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

當(dāng)我們輸入userId="34;drop table user;"后,打印的語(yǔ)句是這樣的:

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

此時(shí),mybatis沒(méi)有使用預(yù)編譯語(yǔ)句,它會(huì)先進(jìn)行字符串拼接再執(zhí)行編譯,這個(gè)過(guò)程正是SQL注入生效的過(guò)程。

因此在編寫(xiě)mybatis的映射語(yǔ)句時(shí),盡量采用“#{xxx}”這樣的格式。若不得不使用“${xxx}”這樣的參數(shù),要手工地做好過(guò)濾工作,來(lái)防止sql注入攻擊。

總結(jié)

以上所述是小編給大家介紹的mybatis防止SQL注入的方法實(shí)例詳解,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • mybatis新增save結(jié)束后自動(dòng)返回主鍵id詳解

    mybatis新增save結(jié)束后自動(dòng)返回主鍵id詳解

    這篇文章主要介紹了mybatis新增save結(jié)束后自動(dòng)返回主鍵id詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java String 和StringBuffer的詳解及區(qū)別

    Java String 和StringBuffer的詳解及區(qū)別

    這篇文章主要介紹了Java String 和StringBuffer的詳解及區(qū)別的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • Java對(duì)象集合按照指定元素順序排序的實(shí)現(xiàn)

    Java對(duì)象集合按照指定元素順序排序的實(shí)現(xiàn)

    最近在對(duì)一個(gè)集合列表的數(shù)據(jù)進(jìn)行排序,需求是要集合數(shù)據(jù)按照一個(gè)排序狀態(tài)值進(jìn)行排序,而這個(gè)狀態(tài)值,不是按照從小到大這樣的順序排序的,而是要按照特定的順序,所以本文給大家介紹了Java對(duì)象集合按照指定元素順序排序的實(shí)現(xiàn),需要的朋友可以參考下
    2024-07-07
  • Java實(shí)現(xiàn)圖片上傳至FastDFS入門(mén)教程

    Java實(shí)現(xiàn)圖片上傳至FastDFS入門(mén)教程

    這篇文章主要介紹了Java實(shí)現(xiàn)圖片上傳至FastDFS入門(mén)教程,通過(guò)前端ajax提交圖片到后端,java處理服務(wù)器文件上傳至FastDFS文件服務(wù)器系統(tǒng),以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • 如何使用IDEA開(kāi)發(fā)Spark SQL程序(一文搞懂)

    如何使用IDEA開(kāi)發(fā)Spark SQL程序(一文搞懂)

    Spark SQL 是一個(gè)用來(lái)處理結(jié)構(gòu)化數(shù)據(jù)的spark組件。它提供了一個(gè)叫做DataFrames的可編程抽象數(shù)據(jù)模型,并且可被視為一個(gè)分布式的SQL查詢(xún)引擎。這篇文章主要介紹了如何使用IDEA開(kāi)發(fā)Spark SQL程序(一文搞懂),需要的朋友可以參考下
    2021-08-08
  • 解決@FeignClient注入service失敗問(wèn)題

    解決@FeignClient注入service失敗問(wèn)題

    這篇文章主要介紹了解決@FeignClient注入service失敗問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • maven解決依賴(lài)沖突的三種解決方法

    maven解決依賴(lài)沖突的三種解決方法

    依賴(lài)沖突是指項(xiàng)目依賴(lài)的某一個(gè)jar包,有多個(gè)不同的版本,因而造成了包版本沖突,本文主要介紹了maven解決依賴(lài)沖突的三種解決方法,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • Java程序命令行參數(shù)用法總結(jié)

    Java程序命令行參數(shù)用法總結(jié)

    這篇文章主要介紹了Java程序命令行參數(shù)用法總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • JDK8安裝與配置實(shí)踐超詳細(xì)指南

    JDK8安裝與配置實(shí)踐超詳細(xì)指南

    本文詳細(xì)介紹了在Windows?64位系統(tǒng)上安裝和配置JDK8的步驟,包括JDK8下載、環(huán)境變量設(shè)置及安裝驗(yàn)證,同時(shí)提供了JDK8新特性如Lambda表達(dá)式、StreamAPI等的概覽,旨在幫助Java開(kāi)發(fā)者有效利用JDK8新特性進(jìn)行開(kāi)發(fā),需要的朋友可以參考下
    2024-10-10
  • JAVA中的構(gòu)造函數(shù)(方法)

    JAVA中的構(gòu)造函數(shù)(方法)

    這篇文章主要介紹了JAVA中的構(gòu)造函數(shù)(方法),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03

最新評(píng)論