预防 SQL 注入
什么是 SQL 注入攻击
假设需要按照商品 title 进行筛选数据,MyBatis\src\main\resources\mappers\goods.xml 下的 <mapper namespace="goods">这么写:
<select id="selectByTitle" parameterType="java.util.Map" resultType="indi.chester.mybatis.entity.Goods">
<!-- ${} 文本替换, 未经任何处理对SQL文本替换, SQL 注入攻击 -->
SELECT * FROM t_goods WHERE title=${title} LIMIT 5
<mapper namespace="goods">
</select>
但如果把传入的title 参数换成"'' or 1=1 or 1=''" 串换成这样:
SELECT * FROM t_goods
WHERE title="'' or 1=1 or 1=''" LIMIT 5
那么 title 的判别条件就会恒成立,因为内部有一个 "1=1"。 这样一句 SQL 语句就可以把数据库所有数据一次性全部提取出来(如果删掉 LIMIT 5)。这种如熬过条件约束,越权获取数据的方实 这就是 SQL 注入攻击。
解决方法
解决方法也很简单, 那就是将 ${参数名} 换成 #{参数名}, 则会在运行时预编译,将'' or 1=1 or 1='' 看作一整个字符串,而不是运行这个字符串。
<select id="selectByTitle" parameterType="java.util.Map" resultType="indi.chester.mybatis.entity.Goods">
<!-- #{} 预编译传值, 防止 SQL 注入攻击 -->
SELECT * FROM t_goods WHERE title=#{title}
</select>
这样如果还是 将 title 参数设置成'' or 1=1 or 1='' 则无法继续访问数据, 除非有一条数据的 title 就是 '' or 1=1 or 1='' .
有的时候需要 ${参数名}
有的时候我们也需要将传入的参数组织成一部分 SQL 语句来运行,而不希望将他看作一个参数。比如我们需要按照 goods_id 降序排序,则需要将 "ORDER BY goods_id DESC" 组织成一段 SQL 语句,而不是当作一个参数。MyBatis\src\main\resources\mappers\goods.xml 下的 <mapper namespace="goods">这么写:
<select id="selectByTitle" parameterType="java.util.Map" resultType="indi.chester.mybatis.entity.Goods">
<!-- 有的时候 使用原文 -->
SELECT * FROM t_goods WHERE title=#{title} ${order}
</select>
在 MyBatis\src\test\java\MyBatisTest.java 添加下面这个方法:
@Test
public void testSelectByTitle() throws Exception{
SqlSession sqlSession=null;
try {
sqlSession=MyBatisUtils.openSession();
Map parm = new HashMap();
//尝试 SQL 注入攻击
//parm.put("title", "'' or 1=1 or 1=''");
//有的时候 使用原文
parm.put("title", "亲润 孕妇护肤品豆乳大米盈润保湿胶原蚕丝面膜(18片装)");
parm.put("order", "ORDER BY goods_id DESC");
List<Goods> goodsList= sqlSession.selectList("goods.selectByTitle", parm);
for (Goods g: goodsList){
System.out.println(g.getGoodsId() +" " + g.getTitle());
}
}catch (Exception e){
if (sqlSession!=null){
sqlSession.rollback();
}
throw e;
}finally {
MyBatisUtils.closeSession(sqlSession);
}
}
运行结果:
21:25:14:725 [main] DEBUG goods.selectByTitle -==> Preparing: SELECT * FROM t_goods WHERE title=? ORDER BY goods_id DESC
21:25:14:755 [main] DEBUG goods.selectByTitle -==> Parameters: 亲润 孕妇护肤品豆乳大米盈润保湿胶原蚕丝面膜(18片装)(String)
21:25:14:784 [main] DEBUG goods.selectByTitle -<== Total: 3
1287 亲润 孕妇护肤品豆乳大米盈润保湿胶原蚕丝面膜(18片装)
1265 亲润 孕妇护肤品豆乳大米盈润保湿胶原蚕丝面膜(18片装)
739 亲润 孕妇护肤品豆乳大米盈润保湿胶原蚕丝面膜(18片装)
Last updated
Was this helpful?