成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【Mybatis系列】從源碼角度理解Mybatis的$和#的作用

yanwei / 601人閱讀

摘要:原因就是傳入的和原有的單引號,正好組成了,而后面恒等于,所以等于對這個庫執(zhí)行了查所有的操作。類比的執(zhí)行流程和原有的我們使用的方法就是??梢岳斫鉃榫褪怯脕斫馕龆ㄖ频姆柕恼Z句。后續(xù)的流程,就和正常的流程一致了。

前言

在JDBC中,主要使用的是兩種語句,一種是支持參數(shù)化和預編譯的PrepareStatement,能夠支持原生的Sql,也支持設置占位符的方式,參數(shù)化輸入的參數(shù),防止Sql注入,一種是支持原生Sql的Statement,有Sql注入的風險。

在使用Mybatis進行開發(fā)過程中,隱藏了底層具體使用哪一種語句的細節(jié),我們通過使用#和$告訴Mybatis,我們實際上進行的是怎么樣的操作,需要對語句進行參數(shù)化還是說直接保持原生狀態(tài)就好。

今天我們主要看一下使用兩種符號使用時系統(tǒng)應對Sql注入的表現(xiàn)和Mybatis在內(nèi)部是如何對他們處理的源碼分析。

和$在應對Sql注入上的區(qū)別表現(xiàn)

利用現(xiàn)有應用程序,將(惡意的)SQL命令注入到后臺數(shù)據(jù)庫引擎執(zhí)行的能力,它可以通過在Web表單中輸入(惡意)SQL語句得到一個存在安全漏洞的網(wǎng)站上的數(shù)據(jù)庫,而不是按照設計者意圖去執(zhí)行SQL語句。

比如說根據(jù)學生姓名查學生信息,會傳入一個name的參數(shù),假設學生姓名是方方,那么Sql就是

SELECT id,name,age FROM student WHERE name = "方方"; 

在沒有做防Sql注入的時候,我們的Sql語句可能是這么寫的

 

正常情況下查出姓名符合方方的學生信息。

但如果我們對傳入的姓名參數(shù)做一些更改,比如改成anything" OR "x"="x,那么拼接而成的Sql就變成了

SELECT id,name,age FROM student WHERE name = "anything" OR "x"="x" 

庫里面所有的學生信息都被拉了出來,是不是很可怕。原因就是傳入的anything" OR "x"="x和原有的單引號,正好組成了 "anything" OR "x"="x",而OR后面恒等于1,所以等于對這個庫執(zhí)行了查所有的操作。

防范Sql注入的話,就是要把整個anything" OR "x"="x中的單引號作為參數(shù)的一部分,而不是和Sql中的單引號進行拼接

使用了#即可在Mybatis中對參數(shù)進行轉(zhuǎn)義

 

我們看一下發(fā)送到數(shù)據(jù)庫端的Sql語句長什么樣子。

SELECT id,name,age FROM student WHERE name = "anything" OR "x"="x" 

從上述代碼中我們可以看到參數(shù)中的所有單引號統(tǒng)統(tǒng)被轉(zhuǎn)移了,這都是JDBC中PrepareStatement的功勞,如果在數(shù)據(jù)庫服務端開啟了預編譯,則是服務端來做了這件事情。

具體可以看我之前寫的這篇: JDBC與Mysql的那些事,里面解釋了為何PrepareStatement能做到這件事情。

源碼

在以前的文章中,我們說明過Mybatis的執(zhí)行流程主要部件,SqlSession 提供給用戶操作的Api,Executor 具體執(zhí)行對數(shù)據(jù)庫的操作,但其實在Executor內(nèi)部還會再委托給StatementHandler這個接口。

這個Handler的實現(xiàn)類就是代表了JDBC中的操作語句,CallableStatementHandler、PrepareStatementHandler和SimpleStatementHandler就會代表對JDBC中的CallableStatement,PrepareStatement和Statement,這些handler的內(nèi)部就會調(diào)用JDBC中的相關Statement。

類比Mybatis的執(zhí)行流程和JDBC原有的我們使用的方法就是。

Mybatis: Sqlsession -> Executor -> StatementHandler -> ResultHandler

JDBC: Connection -> Statement -> Result

因此我們可以知道對JDBC語句的操作都會在StatementHandler內(nèi)部。

在PrepareStatementHandler中會使用paramterize對Statement進行參數(shù)化,在其中他會委托給DefualtParameterHandler進行操作。我們通過兩種不同的語句,看一下,Debug下這段代碼的不同。

首先是使用$符號,它是會直接在Sql中進行拼接的,從下圖可知,在進行參數(shù)化的時候,Sql語句已經(jīng)被拼接完成了,見originSql。

進入DefualtParameterHandler內(nèi)部,如下圖可知,我們看到,這兒boundSql的ParameterMappings不存在,所以不用執(zhí)行第二個紅框處,設置對應占位符的操作。

然后,我們看一下當使用#的時候,同樣的代碼,會得到什么樣的處理結果。從下圖可知,當使用#的時候,原有的#{value}被替換成了?號,也就是我們熟知的JDBC中的占位符。

再進入DefualtParameterHandler的時候, 此時會有ParameterMappings,value -> anything" OR "x"="x",找到合適的TypeHandler塞入PrepareStatement中。

**從上文的分析中,我們得到的就是,當使用的時候,的時候,{value},是直接被替換為了對應的值,沒有參數(shù)映射,不會進行設置占位符的操作,當使用#的時候,#{}會被替換為?號,有參數(shù)映射,會在DefaultParameterHandler中進行設置占位符的操作。

問題

1 為什么默認使用的語句是PrepareStatementHandler

2 和#是什么時候被替換的,為什么對應的BoundSql,$時沒有映射,#有映射。

帶著這兩個問題我們來看一下,Mybatis的初始化階段,為節(jié)省篇幅,僅列出大致路徑,和關鍵代碼。

Mybatis是通過SqlSessionFactory build出來的,會解析映射文件,大致路徑就是

SqlSessionFactoryBuilder -> XmlConfigBuilder->XMLMapperBuilder->XMLStatementBuilder。

在XMLStatementBuilder的parseStatementNode負責了生成MappedStatement,首先回答第一個問題。當你不指定statementType時,Mybatis默認使用的就是PrepareStatementHandler,這里的StatementType,在后續(xù)流程中使用RoutingStatementHandler選擇使用哪一個StatementHandler。

然后繼續(xù)看第二個問題,$和#是怎么被替換的。

在之前我們提到了,BoundSql中包含了Sql主體,同時其中的參數(shù)映射決定了后續(xù)是否要進行參數(shù)化,在$和#時,表現(xiàn)是不同的。

BoudSql來自于MappedStatement,在MappedStatement中,獲取BoundSql的任務會委托給SqlSource接口。所以我們接下來主要看SqlSource是如何生成的。

XMLLandDriver可以理解為就是用來解析Mybatis定制的XML符號的語句。他會把具體解析符號的職責交給XMLScriptBuilder的parseScriptNode方法。

parseDynamicTags中會把語句用TextSql包裝起來,然后使用isDynamic方法,在方法中使用GerenericTokenParser判斷是否是動態(tài)語句。如果其中包含$,就是動態(tài)的,如果是#就不是動態(tài)的,使用的Handler是DrynamicCheckerTokenParser。

在進入parse方法后,主要看以下這一段。

這里會使用TokenHandler不同的實現(xiàn)類,對表達式進行進一步的處理,這里是對Sql自后的完善,在判斷isDynamic中,使用的是DrynamicCheckerTokenParser,一個最簡單的實現(xiàn)。

parse完成后,如果isDynamic是true的話,就是動態(tài)語句,使用DynamicSqlSource。

如果是非動態(tài)的話,其實一般就是指使用了#的語句,使用RawSqlSource,在其中,還會進一步解析。

從下圖中可以看到,這個TokenParser這回使用的是#{},而且使用的是ParameterMappingTokenHandler。

ParameterMappingTokenHandler的handlerToken方法中,完成了添加參數(shù)映射和替換#{value}為?的職責。

從以上我們可以知道,使用#在初始化階段,會被替換成?號,同時生成參數(shù)映射,而使用$在初始化階段,沒有什么特別的地方,僅僅做了一個是否動態(tài)語句的判斷。

在初始化完畢后,我們進入getBoundSql方法,看一下DynamicSqlSource和StaticSource在此刻做了什么,首先是DynamicSqlSource。

在其中,首先會生成一個DynamicContext,主要就是 生成bindings,一個是 "_parameter" -> "anything" OR "x"="x",一個是"_databaseId" -> "null"

然后使用了apply方法,我理解這里是要去做替換了。具體還是使用${}去判斷,和上文一致,只不過這里使用的是BindingTokenParser。

看一下BindingTokenParser的HandleToken方法。

上述代碼的效果,就是會使用Ognl,使用value在Bindings中,找對應的值,最后返回,拼接在Sql中,這也就是為什么會有Sql注入風險的原因。使用value是因為Ognl去找的時候,就會使用value這個默認值,所以需要在bindings額外加入這么一個鍵值對,有興趣可以繼續(xù)往下看ONGL相關的東西。

接下來是生成SqlSource,使用的是SqlSourceBuilder的parse方法。

在前文介紹過,在這個parse方法里,是用#{}來判斷的,所以走不到ParameterMappingTokenHandler的handlerToken方法,也就無法添加參數(shù)映射了,這個直接返回一個StaticSqlSource,這也解釋了為什么使用$時,參數(shù)映射為空。

再接下去就是獲取BoundSql,使用的是StaticSqlSource,直接根據(jù)參數(shù),實例化了一個,參數(shù)映射為空。

當使用#的時候,使用的就是StaticSqlSource,直接實例化,因為參數(shù)映射在之前初始化的階段,也生成好了,所以很簡單的一個流程。

后續(xù)的流程,就和Mybatis正常的流程一致了。

總結

本文主要剖析了Mybatis中$和#兩種符號使用上的不同,以及使用這兩種符號時,源碼流程上的區(qū)別。建議大家都使用#號,在orm這層也規(guī)避到Sql注入的風險。

倘若您有疑問或者有進一步想了解內(nèi)容,歡迎留言給我。

文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/67332.html

相關文章

  • Mybatis系列源碼角度理解Mybatis數(shù)據(jù)轉(zhuǎn)換器TypeHandler

    摘要:無論是在預處理語句中設置一個參數(shù)時,還是從結果集中取出一個值時,都會用類型處理器將獲取的值以合適的方式轉(zhuǎn)換成類型。這個抽象類實現(xiàn)了接口,這個接口主要定義了類型轉(zhuǎn)換的幾種操作。至于這個抽象類繼承的,主要是提供了獲取這個具體是哪個類型。 TypeHandlers 無論是 MyBatis 在預處理語句(PreparedStatement)中設置一個參數(shù)時,還是從結果集中取出一個值時, 都會用...

    Edison 評論0 收藏0
  • Mybatis系列源碼角度理解Mybatis字段映射-AS&ResultMap

    摘要:北京解決辦法在字段的時候使用,下面是改動后的映射文件。北京那么我們來看看它是如何生效的,主要的代碼在哪里。源碼層面的話,依舊在的中處理返回集合。總結大致上,完成映射主要是兩種方式。使用預先定義好映射關系,也是最后根據(jù)和反射,完成字段的賦值。 前言 考慮到在Select時使用AS和方案一其實沒什么差別,在介紹ResultMap之前,順便帶過一下。 方案二-Select .... AS 當...

    Zhuxy 評論0 收藏0
  • Java深入-框架技巧

    摘要:從使用到原理學習線程池關于線程池的使用,及原理分析分析角度新穎面向切面編程的基本用法基于注解的實現(xiàn)在軟件開發(fā)中,分散于應用中多出的功能被稱為橫切關注點如事務安全緩存等。 Java 程序媛手把手教你設計模式中的撩妹神技 -- 上篇 遇一人白首,擇一城終老,是多么美好的人生境界,她和他歷經(jīng)風雨慢慢變老,回首走過的點點滴滴,依然清楚的記得當初愛情萌芽的模樣…… Java 進階面試問題列表 -...

    chengtao1633 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<