1 引言
对于很多初学者而言,SQL注入攻击是一种很容易被忽略的安全漏洞,其原理很简单,在日常编码中需要注意规避,养成良好的系统安全意识。
2 原理
SQL注入漏洞产生的根本原因,就是在编码过程中手动拼接sql参数造成的。
看下面的例子:模拟登录场景,账号是admin,密码未知,但是我们可以输入一个恒等式:’ OR 1=1作为密码。如果这时候通过拼接的方式构造sql,这个sql的条件就是一定成立的,如此我们就可以成功登录任意账号,这就是SQL注入攻击。
String account = "admin";
String password = "' OR 1=1";
String sql = "SELECT * FROM t_sys_user WHERE account = '" + account + "' AND password = '" + password;
System.out.println(sql);
//SELECT * FROM t_sys_user WHERE account = 'admin' AND password = '' OR 1=1
3 规避
3.1 重要的事说三遍
- 不要手动拼接sql参数
- 不要手动拼接sql参数
- 不要手动拼接sql参数
3.2 Hibernate
- 对于ORM一类的框架来说,尽量使用JPA自带的方法来传参,如q.setParameter(key, params.get(key));
@Override
public <T> List<T> find(String hql, Map<String, Object> params) {
Query q = entityManager.createQuery(hql);
if (null != params && !params.isEmpty()) {
for (String key : params.keySet()) {
q.setParameter(key, params.get(key));
}
}
return q.getResultList();
}
3.3 Mybatis
- 使用QueryWrappe时,尽量使用自带的方法来传参,如 q.eq(“account”, search);
@Override
public Object listPage(Param param) {
String search = param.getString("search");
QueryWrapper<User> q = new QueryWrapper<>();
q.eq("delFlag", 0);
q.eq("account", search);
q.orderByDesc("id");
User user= userMapper.selectOne(q);
return user;
}
- 使用mapper.xml时,注意使用#{}传参,不要使用${}传参
1, #{}使用了预处理的方式,因此它可以有效地防止SQL注入攻击
2, ${}是简单的字符串替换,有SQL注入的风险
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zeroone.mapper.master.UserMapper">
<select id="selectAllPage" parameterType="java.util.Map" resultType="java.util.Map">
select * from t_user_a
<where>
<if test="param.search!= null and param.search!= ''">
account = #{param.search}
</if>
</where>
</select>
</mapper>
3.4 字符串过滤
替换参数中的特殊符号,比如下列方法
obj.replaceAll("([';])+|(--)+", "")