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