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(); }