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

Mybatis常用注解中的SQL注入實(shí)例詳解

 更新時(shí)間:2022年02月14日 14:14:51   作者:江湖大俠  
MyBatis是一款優(yōu)秀的持久層框架,它支持定制化 SQL(靈活)、存儲(chǔ)過(guò)程(PLSQL模塊化的組件,數(shù)據(jù)庫(kù)的一部分)以及高級(jí)映射(表映射為Bean也可以將Bean映射為表),下面這篇文章主要給大家介紹了關(guān)于Mybatis常用注解中的SQL注入的相關(guān)資料,需要的朋友可以參考下

前言

MyBatis3提供了新的基于注解的配置。主要在MapperAnnotationBuilder中,定義了相關(guān)的注解:

public MapperAnnotationBuilder(Configuration configuration, Class<?> type) {
    ...
    sqlAnnotationTypes.add(Select.class);
    sqlAnnotationTypes.add(Insert.class);
    sqlAnnotationTypes.add(Update.class);
    sqlAnnotationTypes.add(Delete.class);
    ......
    sqlProviderAnnotationTypes.add(SelectProvider.class);
    sqlProviderAnnotationTypes.add(InsertProvider.class);
    sqlProviderAnnotationTypes.add(UpdateProvider.class);
    sqlProviderAnnotationTypes.add(DeleteProvider.class);
}

增刪改查占據(jù)了絕大部分的業(yè)務(wù)操作,通過(guò)注解不在需要配置繁雜的xml文件,越來(lái)越多的sql交互均通過(guò)注解來(lái)實(shí)現(xiàn)。從MapperAnnotationBuilder可以看到Mybatis提供了以下相關(guān)的注解:

  • @Select
  • @Insert
  • @Update
  • @Delete
  • @SelectProvider
  • @InsertProvider
  • @UpdateProvider
  • @DeleteProvider

例如如下例子,使用@Select注解直接編寫(xiě)SQL完成數(shù)據(jù)查詢:

@Mapper
public interface UserMapper {    
@Select("select * from t_user")    
List<User> list();
}

使用類似@SelectProvider高級(jí)注解可以指定某個(gè)工具類的方法來(lái)動(dòng)態(tài)編寫(xiě)SQL,以應(yīng)對(duì)復(fù)雜的業(yè)務(wù)需求。
以@SelectProvider 為例,查看具體的實(shí)現(xiàn),主要包含兩個(gè)注解屬性,其中type表示工具類,method 表示工具類的某個(gè)方法,用于返回具體的SQL:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface InsertProvider {
    // 用于指定獲取 sql 語(yǔ)句的指定類
    Class<?> type();
    // 指定類中要執(zhí)行獲取 sql 語(yǔ)句的方法
    String method();
}

使用方法如下,在ProjectSql類的getContentByProjectIds方法定義相關(guān)的sql即可,sql的定義可以通過(guò)org.apache.ibatis.jdbc.SQL來(lái)快速實(shí)現(xiàn):
@SelectProvider(type = ProjectSql.class, method = "getContentByProjectIds")
List<Integer> getContentByProjectIds(List<Integer> projectIds);

常見(jiàn)注入場(chǎng)景

2.1普通注解

實(shí)際上跟xml配置中對(duì)應(yīng)的標(biāo)簽語(yǔ)法是一樣的(例如@Select對(duì)應(yīng)<select>標(biāo)簽),所以注入場(chǎng)景也是類似的。

在Mybatis中,#的作用主要是替換預(yù)編譯語(yǔ)句(PrepareStatement)中的占位符?,$是直接的SQL拼接。以like模糊查詢 為例子:

例如如下例子:

跟xml配置一樣,like模糊查詢直接使用#預(yù)編譯的方式進(jìn)行注解的話會(huì)觸發(fā)異常,所以很多時(shí)候直接使用$進(jìn)行注解:

@Select("SELECT id, name, age, email FROM user where name like '${name}'")List<User> queryUserByName(@Param("name") String name);

那么此時(shí)name前端用戶可控的話,將導(dǎo)致SQL注入風(fēng)險(xiǎn)。

圖片查看sql日志,成功執(zhí)行1/0觸發(fā)sql error,說(shuō)明注入成功:

處理這類SQL問(wèn)題也很簡(jiǎn)單,使用sql的內(nèi)置函數(shù)進(jìn)行拼接,拼接后再采用#預(yù)編譯的方式進(jìn)行查詢。例如上面案例是h2數(shù)據(jù)庫(kù)的,使用'||'拼接再進(jìn)行預(yù)編譯處理即可:

@Select("SELECT id, name, age, email FROM user where name like '%'||#{name}||'%'")List<User> queryUserByName(@Param("name") String name);

此時(shí)已使用預(yù)編譯進(jìn)行SQL查詢:

此外,類似Order by、動(dòng)態(tài)表名,無(wú)法采用預(yù)編譯的方式情況,可以在在代碼層使用間接引用的方式進(jìn)行處理。

對(duì)于范圍查詢in,熟悉mybatis注入的話,是需要使用MyBatis自帶的循環(huán)指令foreach來(lái)解決SQL語(yǔ)句動(dòng)態(tài)拼接的,當(dāng)使用注解時(shí),就需要使用< script>標(biāo)簽來(lái)引入foreach了。

2.2 動(dòng)態(tài)sql

2.2.1 使用< script>

要在帶普通注解的映射器接口類中使用動(dòng)態(tài) SQL,可以使用script 元素。跟xml類似,主要是如下的元素:

if
choose (when, otherwise)
trim (where, set)
foreach

相關(guān)的注入場(chǎng)景跟2.1也是類似的。也是離不開(kāi)$。此外,在進(jìn)行同條件多值查詢(例如范圍查詢in)的時(shí)候,可以使用MyBatis自帶的循環(huán)指令foreach來(lái)解決SQL語(yǔ)句動(dòng)態(tài)拼接的問(wèn)題。

2.2.2 使用Provider注解

可以通過(guò)使用Provider注解指定某個(gè)工具類的方法來(lái)動(dòng)態(tài)編寫(xiě)SQL。以@SelectProvider為例:

首先在mapper中使用@SelectProvider定義相關(guān)的方法,其中type表示工具類,method 表示工具類的某個(gè)方法,用于返回具體的SQL。例如下面的例子:
通過(guò)傳遞userIds以及name,查詢相關(guān)的用戶信息,在UserInfoSql類的getUserInfoByids方法定義了具體的SQL內(nèi)容:

/**
   * @param userIds 必填
   * @param name 可選
   * @return
   */
  @SelectProvider(type = UserInfoSql.class, method = "getUserInfoByids")
  List<User> getUserInfoByids(List<Long> userIds, String name);
   
  class UserInfoSql {
    public String getUserInfoByids(List<Long> userIds, String name) {
      SQL sql = new SQL();
      sql.SELECT("id, name, age, email");
      sql.FROM("user");
      sql.WHERE("id in(" + Joiner.on(',').join(userIds) + ")");
      if(StringUtil.isNotBlank(name)){
        sql.WHERE("name like '%" + name + "%'");
      }
      sql.ORDER_BY("id desc");
      return sql.toString();
    }
  }

在Controller調(diào)用具體方法就可以進(jìn)行sql查詢了:

@RequestMapping(value = "/getUserInfoByids")
 public List<User> getUserInfoByids(String name,@RequestParam List<Long> userIds){
         List<User> userList = userMapper.getUserInfoByids(userIds,name);
         return userList;
 }

正常請(qǐng)求返回對(duì)應(yīng)的用戶信息:

前面是通過(guò)MyBatis 3 提供的工具類org.apache.ibatis.jdbc.SQL來(lái)生成SQL的。該類提供了類似select、where、ORDER_BY等方法來(lái)完成SQL生成的操作。這里有個(gè)誤區(qū),很多開(kāi)發(fā)認(rèn)為這里工具類會(huì)進(jìn)行相關(guān)的預(yù)編譯處理。

實(shí)際上Provider其實(shí)只需要返回一個(gè)SQL字符串,工具類只不過(guò)用了一些關(guān)鍵字做格式化而已,甚至可以直接使用StringBuffer拼接SQL語(yǔ)句。同樣是上面的例子,List userIds是long類型,但是name是String類型,可以嘗試注入:

查看相關(guān)日志,成功執(zhí)行1/0邏輯觸發(fā)SQL error,也印證了Provider實(shí)際上只是 SQL 拼接,沒(méi)有做相關(guān)的安全處理 :

相比@Select@,SelectProvider 只是在定義注解的方式上有所不同, 前者是直接定義 sql, 一個(gè)是在外部定義好 sql 直接引用, 沒(méi)本質(zhì)上的區(qū)別,所以解決方法是在對(duì)應(yīng)的sql場(chǎng)景,使用#進(jìn)行預(yù)編譯進(jìn)行處理,例如這里的like模糊查詢和in范圍查詢:

@SelectProvider(type = UserInfoSql.class, method = "getUserInfoByids")
  List<User> getUserInfoByids(@Param("userIds")List<Long> userIds,@Param("name")String name);
   
  class UserInfoSql {
    public String getUserInfoByids(@Param("userIds")List<Long> userIds, @Param("name")String name) {
            StringBuilder sql = new StringBuilder(128);
            sql.append("< script>SELECT id, name, age, email FROM user WHERE (id in");
            sql.append("<foreach item='item' collection='userIds' open='(' separator=',' close=')'>#{item}</foreach>");
      if(StringUtil.isNotBlank(name)){
              sql.append("and name like '%'||#{name}||'%')");
      }
      sql.append("ORDER BY id desc</script>");
      return sql.toString();
    }
  }

查看sql日志,此時(shí)使用預(yù)編譯進(jìn)行sql處理,避免了SQL注入風(fēng)險(xiǎn)。

總結(jié)

到此這篇關(guān)于Mybatis常用注解中的SQL注入的文章就介紹到這了,更多相關(guān)Mybatis注解的SQL注入內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解析Arthas協(xié)助排查線上skywalking不可用問(wèn)題

    解析Arthas協(xié)助排查線上skywalking不可用問(wèn)題

    這篇文章主要為大家介紹了解析Arthas協(xié)助排查線上skywalking不可用的問(wèn)題詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-02-02
  • DTD驗(yàn)證xml格式的三種方式詳解

    DTD驗(yàn)證xml格式的三種方式詳解

    這篇文章主要介紹了DTD驗(yàn)證xml格式的三種方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • RabbitMQ實(shí)現(xiàn)消息可靠性傳遞過(guò)程講解

    RabbitMQ實(shí)現(xiàn)消息可靠性傳遞過(guò)程講解

    消息的可靠性傳遞是指保證消息百分百發(fā)送到消息隊(duì)列中去,這篇文章主要介紹了RabbitMQ實(shí)現(xiàn)消息可靠性傳遞過(guò)程,感興趣想要詳細(xì)了解可以參考下文
    2023-05-05
  • SpringBoot實(shí)現(xiàn)文件上傳下載實(shí)時(shí)進(jìn)度條功能(附源碼)

    SpringBoot實(shí)現(xiàn)文件上傳下載實(shí)時(shí)進(jìn)度條功能(附源碼)

    這篇文章主要為大家詳細(xì)介紹了SpringBoot如何實(shí)現(xiàn)文件上傳下載實(shí)時(shí)進(jìn)度條功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以學(xué)習(xí)一下
    2022-10-10
  • 老生常談Eclipse中的BuildPath(必看篇)

    老生常談Eclipse中的BuildPath(必看篇)

    下面小編就為大家?guī)?lái)一篇老生常談Eclipse中的BuildPath(必看篇)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-06-06
  • Springboot 整合RabbitMq(用心看完這一篇就夠了)

    Springboot 整合RabbitMq(用心看完這一篇就夠了)

    這篇文章主要介紹了Springboot 整合RabbitMq(用心看完這一篇就夠了),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • SpringBoot?常用讀取配置文件的三種方法詳解

    SpringBoot?常用讀取配置文件的三種方法詳解

    這篇文章主要介紹了SpringBoot?常用讀取配置文件的3種方法,通過(guò)本文學(xué)習(xí)可以解決Spring Boot有哪些常用的讀取配置文件方式,一些復(fù)雜的數(shù)據(jù)結(jié)構(gòu),如list,map如何配置,帶著這些問(wèn)題一起通過(guò)本文學(xué)習(xí)吧
    2022-09-09
  • Java之dao模式詳解及代碼示例

    Java之dao模式詳解及代碼示例

    這篇文章主要介紹了Java之dao模式詳解及代碼示例,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11
  • Java Flink與kafka實(shí)現(xiàn)實(shí)時(shí)告警功能過(guò)程

    Java Flink與kafka實(shí)現(xiàn)實(shí)時(shí)告警功能過(guò)程

    這篇文章主要介紹了Java Flink與kafka實(shí)現(xiàn)實(shí)時(shí)告警功能,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-01-01
  • Hibernate中獲取Session的兩種方式代碼示例

    Hibernate中獲取Session的兩種方式代碼示例

    這篇文章主要介紹了Hibernate中獲取Session的兩種方式代碼示例,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-12-12

最新評(píng)論