MyBatis3提供了新的基于注解的配置。主要在MapperAnnotationBuilder中,定义了相关的注解:
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);
}
-
@Select -
@Insert -
@Update -
@Delete -
@SelectProvider -
@InsertProvider -
@UpdateProvider -
@DeleteProvider
public interface UserMapper {
"select * from t_user") (
List<User> list();
}
(RetentionPolicy.RUNTIME)
(ElementType.METHOD)
public InsertProvider {
// 用于指定获取 sql 语句的指定类
Class<?> type();
// 指定类中要执行获取 sql 语句的方法
String method();
}
@SelectProvider(type = ProjectSql.class, method = "getContentByProjectIds")
List<Integer> getContentByProjectIds(List<Integer> projectIds);
@Select("SELECT id, name, age, email FROM user where name like '${name}'")List<User> queryUserByName(@Param("name") String name);
那么此时name前端用户可控的话,将导致SQL注入风险。
查看sql日志,成功执行1/0触发sql error,说明注入成功:
处理这类SQL问题也很简单,使用sql的内置函数进行拼接,拼接后再采用#预编译的方式进行查询。例如上面案例是h2数据库的,使用'||'拼接再进行预编译处理即可:
@Select("SELECT id, name, age, email FROM user where name like '%'||#{name}||'%'")List<User> queryUserByName(@Param("name") String name);
此时已使用预编译进行SQL查询:
此外,类似Order by、动态表名,无法采用预编译的方式情况,可以在在代码层使用间接引用的方式进行处理。 对于范围查询in,熟悉mybatis注入的话,是需要使用MyBatis自带的循环指令foreach来解决SQL语句动态拼接的,当使用注解时,就需要使用< script>标签来引入foreach了。 2.2 动态sql
2.2.1 使用< script>
要在带普通注解的映射器接口类中使用动态 SQL,可以使用script 元素。跟xml类似,主要是如下的元素:
if choose (when, otherwise) trim (where, set) foreach 相关的注入场景跟2.1也是类似的。也是离不开$。此外,在进行同条件多值查询(例如范围查询in)的时候,可以使用MyBatis自带的循环指令foreach来解决SQL语句动态拼接的问题。 2.2.2 使用Provider注解
可以通过使用Provider注解指定某个工具类的方法来动态编写SQL。以@SelectProvider为例: 首先在mapper中使用@SelectProvider定义相关的方法,其中type表示工具类,method 表示工具类的某个方法,用于返回具体的SQL。例如下面的例子: 通过传递userIds以及name,查询相关的用户信息,在UserInfoSql类的getUserInfoByids方法定义了具体的SQL内容:
/**
* @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调用具体方法就可以进行sql查询了:
public List<User> getUserInfoByids(String name, List<Long> userIds){
List<User> userList = userMapper.getUserInfoByids(userIds,name);
return userList;
}
正常请求返回对应的用户信息:
前面是通过MyBatis 3 提供的工具类org.apache.ibatis.jdbc.SQL来生成SQL的。该类提供了类似select、where、ORDER_BY等方法来完成SQL生成的操作。这里有个误区,很多开发认为这里工具类会进行相关的预编译处理。 实际上Provider其实只需要返回一个SQL字符串,工具类只不过用了一些关键字做格式化而已,甚至可以直接使用StringBuffer拼接SQL语句。同样是上面的例子,List userIds是long类型,但是name是String类型,可以尝试注入:
查看相关日志,成功执行1/0逻辑触发SQL error,也印证了Provider实际上只是 SQL 拼接,没有做相关的安全处理 :
相比@Select@,SelectProvider 只是在定义注解的方式上有所不同, 前者是直接定义 sql, 一个是在外部定义好 sql 直接引用, 没本质上的区别,所以解决方法是在对应的sql场景,使用#进行预编译进行处理,例如这里的like模糊查询和in范围查询:
List<User> getUserInfoByids(Long> userIds, String name); List<
class UserInfoSql {
public String getUserInfoByids( List<Long> userIds, 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日志,此时使用预编译进行sql处理,避免了SQL注入风险:
结语
mybatis3提供了新的基于注解的配置。实际上在sql注入的防护以及框架规范使用上跟xml还是类似的,在实际开发或者审计时可以关注对应注解的实现,避免sql注入风险。
原创 |【胖哈勃的七月公开赛】NewSql
原创 | 记一次完成的钓鱼实战
原创 | AMSI 浅析及绕过
本文始发于微信公众号(SecIN技术平台):原创 | Mybatis常用注解中的SQL注入
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论