java审计-mybatis注入审计

基础

  • Mybatis获取值的方式有两种,分别是${} 和 #{}。在Mybatis里面一般会采用#{}来进行取值,但是也会有特殊情况。

    • #{}:解析的是占位符问号,可以防止SQL注入,使用了预编译。
    • ${}:直接获取值

例子

like预编译

  • 使用like语句时直接使用#{}会报错,可能会存在使用${}直接拼接,造成sql注入

  • 直接写法

    <select id="findByUserNameVuln02" parameterType="String" resultMap="User">
        select * from users where username like '%${_parameter}%'
    </select>
    

    在这里插入图片描述

  • 报错写法

    <select id="findByUserNameVsec02" parameterType="String" resultMap="User">
        select * from users where username like '%#{_parameter}%'
    </select>
    
  • 正确写法

     <select id="findByUserNameVsec02" parameterType="String" resultMap="User">
         select * from users where username like concat('%',#{_parameter}, '%')
     </select>
    
  • 其他数据库

    mysql:
        select * from users where username like concat('%',#{username},'%')
    oracle:
        select * from users where username like '%'||#{username}||'%'
    sqlserver:
        select * from users where username like '%'+#{username}+'%'
    

in预编译

  • 使用in语句时直接使用#{}会报错,可能会存在使用${}直接拼接,造成sql注入

  • 直接写法

    <select id="findByUserNameVuln04" parameterType="String" resultMap="User">
        select * from users where id in (${ids})
    </select>
    

    在这里插入图片描述

  • 错误写法

    <select id="findByUserNameVuln04" parameterType="String" resultMap="User">
        select * from users where id in (${ids})
    </select>
    
  • 正确写法

    http://localhost:8080/sqli/mybatis/ids/vsec04?ids=1,2
    
    @GetMapping("/mybatis/ids/vsec04")
    public List<User> mybatisVsec04(@RequestParam("ids") String ids) {
    
        return userMapper.findByUserNameVsec04(ids);
    }
    
    <select id="findByUserNameVsec04" parameterType="String" resultMap="User">
        select * from users where id in
        <foreach collection="ids.split(',')" item="item" separator="," open="(" close=")">#{ids} </foreach>
    </select>
    

order by

  • 使用order by语句时直接使用#{}会报错,可能会存在使用${}直接拼接,造成sql注入

  • 用order by语句时,尽量后端写死

  • 错误写法

    <select id="findByUserNameVuln03" parameterType="String" resultMap="User">
       select * from users
       <if test="order != null">
           order by ${order} asc
       </if>
    </select>
    

    在这里插入图片描述

  • 正确写法,写死

     <select id="OrderByUsername" resultMap="User">
         select * from users order by id asc limit 1
     </select>
    
  • 正确写法,过滤

    Java代码块:
    @GetMapping("/mybatis/orderby/sec04")
    public List<User> mybatisOrderBySec04(@RequestParam("sort") String sort) {
        String filter_order = SecurityUtil.sqlFilter(sort);
        return userMapper.findByUserNameVuln03(filter_order);
    }//sqlFilter
    private static final Pattern FILTER_PATTERN = Pattern.compile("^[a-zA-Z0-9_/\.-]+$");
     
    public static String sqlFilter(String sql) {
        if (!FILTER_PATTERN.matcher(sql).matches()) {  //严格限制用户输入只能包含a-zA-Z0-9_-.
            return null;
        }
        return sql;
    }Mysql配置:
        
    <select id="findByUserNameVuln03" parameterType="String" resultMap="User">
        select * from users
        <if test="order != null">
            order by ${order} asc
        </if>
    

Hibernate

  • hibernate即我们经常使用的orm的一种实现,如果使用已封装好的方法,那么默认是使用预编译的。需要注意的有这么几种情况:

    • 对于一些复杂的sql语句,需要开发手写sql,此时要严格过滤用户输入。
    • 上面提到的预编译不生效的几种场景。
    @Autowired CategoryDAO categoryDAO; //依赖注入@RequestMapping("/hibernate")
    public String hibernate(@RequestParam(name = "id") int id) {
      Category category = categoryDAO.getOne(id);
      return category.getName();
    }
    

你可能感兴趣的:(mybatis,java,mysql,系统安全,代码复审)