一、什么是预编译
普通sql语句执行过程:提交SQL语句 -> 数据库引擎对SQL语句进行编译得到数据库可执行的代码 -> 执行SQL代码;
预编译:SQL语句发送给DBMS,由DBMS首先进行编译后再执行。预编译语句和Statement不同,在创建PreparedStatement 对象时就指定了SQL语句,该语句立即发送给DBMS进行编译。当该编译语句被执行时,DBMS直接运行编译后的SQL语句,而不需要像其他SQL语句那样首先将其编译。
二、Jdbc预编译、框架Mybatis预编译
1.Jdbc预编译
Jdbc预编译
String sql = "SELECT * FROM user WHERE id = '" + id + "'";
Statement statement = connection.createStatement();
statement.execute(sql);
String sql = "SELECT * FROM user WHERE id = ?";
//预编译语句
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//填入参数
preparedStatement.setString(1,reqStuId);
preparedStatement.executeQuery();
构造请求 /?id='or 1 # 预编译的不会出现问题,执行的SQL会变成 SELECT * FROM user WHERE id = ''or 1 #'
2.框架Mybatis预编译
直接拼接写法
WHERE stu_id = ${stuId}
预编译写法
SELECT * FROM student WHERE stu_id = #{stuId}
三、存在的问题
预编译对ORDER BY子句、表名、列名不生效。
通过占位符传参,不管传递的是什么类型的值,都会被单引号包裹。而使用 ORDER BY 时,要求传入的是字段名或者是字段位置,传入的是引号包裹的字符串,那么 ORDER BY 会失效,如:SELECT * FROM user ORDER BY 'id'
类似的, GROUP BY 也会有同样的问题。最后引用下P师傅总结
MyBatis 预编译模式的实现,在底层同样是依赖于 java.sql.PreparedStatement,所以 PreparedStatement 存在的问题,这里也会存在。
四、参考链接
https://mp.weixin.qq.com/s/l2Bt9jv-96HapqxYfeju2w
https://www.huaweicloud.com/articles/0613297d897534a6322641e0b3d30ff8.html
https://github.com/langligelang/dragonfly
原文始发于微信公众号(赛博少女):预编译后SQL注入仍旧存在
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论