SQL注入
针对web安全问题,需要将项目中mybatis涉及${}的代码全部改成#{},由于涉及$的代码多是in和like,现在提供以下解决思路
in和like的场景
模糊查询,涉及多个字段
name like '%${name}%'
条件查询 String ids; // ids:1,2,3
形如id这样类型为int的字段
id in (${ids})
通过instr处理like场景的sql注入
针对name like ‘%${name}%’ 这样的模式查询
使用sql内建函数
instr(str, substr[, position[, occurrence]])替代
- str:源字符
- substr:目标字符
- position:初始索引
- occurrence:出现次数
instr(name, #{name,jdbcType=VARCHAR})>0 替代 name like '%${name}%'
使用instr的优势在于,当数据量很多时instr的效率比like要高(索引对instr有效)
注意:此方式只能出来like模糊查询的sql注入问题
通过校验参数处理in场景的sql注入
针对id in (${ids})这样条件查询中插入的语句,在代码中对参数进行校验
/**
* Created by white_while
* @author white_while
*/
public class CheckSqlParam {
private CheckSqlParam() {}
public static boolean checkParam(Map<Object, Object> paramMap, Set<String> ids) {
boolean outcome = true;
// 校验一下数据库类型为int的参数是否存在sql注入的风险
Map<String, Object> result = new HashMap<String, Object>(){{
put("param", null);
}};
try {
paramMap.entrySet().stream().forEach(entry -> {
boolean flag = ids.contains(entry.getKey());
if (flag) {
result.put("param", entry);
String str = (String) entry.getValue();
// 将参数强转为int,若报错则传入参数有误
Arrays.stream(str.split(",")).forEach(Integer::parseInt);
}
});
} catch (NumberFormatException e) {
outcome = false;
}
return outcome;
}
}
调用方:
public Result getPojosOnCondition(Map<Object, Object> pojoMap) {
// 校验一下参数是否存在sql注入的风险
// ids applicationId userIds
Set<String> ids = new HashSet<String>(Arrays.asList("ids", "applicationId", "userIds"));
boolean outcome = CheckSqlParam.checkParam(pojoMap, ids);
if (!outcome) {
return new Result("参数有误");
}
...
}
注意:此方式只能处理用于in的数据库类型为int的参数