Mybatis如何防止SQL注入

更新时间:2023-07-20 08:42:01 阅读: 评论:0

Mybatis如何防⽌SQL注⼊间接抒情
什么是SQL注⼊攻击
SQL注⼊,⼤家都不陌⽣,是⼀种常见的攻击⽅式。攻击者在界⾯的表单信息或URL上输⼊⼀些奇怪的SQL⽚段(例如“or
‘1’=’1’”这样的语句),有可能⼊侵参数检验不⾜的应⽤程序。所以,在我们的应⽤中需要做⼀些⼯作,来防备这样的攻击⽅式。例如攻击者会将passwd的参数输⼊为“ ’ or ‘1’ = '1 ”;那么直接使⽤Statement,则打印出来的SQL语句如下:
lect * from tb_name ='随意' and passwd ='' or '1'='1';
因为’1’='1’肯定成⽴,所以可以任何通过验证.
mybatis中的#和$的区别:
先看两个SQL语句:
<lect id="lectByNameAndPassword" parameterType="java.util.Map" resultMap="BaResultMap">
lect id, urname, password, role
容易口渴from ur
where urname =#{urname,jdbcType=VARCHAR}
and password =#{password,jdbcType=VARCHAR}
</lect>
<lect id="lectByNameAndPassword" parameterType="java.util.Map" resultMap="BaResultMap">
lect id, urname, password, role
from ur
where urname = ${urname,jdbcType=VARCHAR}
and password = ${password,jdbcType=VARCHAR}
</lect>
1、#将传⼊的数据都当成⼀个字符串,会对⾃动传⼊的数据加⼀个双引号。
杨绛传读后感
如:where urname=#{urname},如果传⼊的值是111,那么解析成sql时的值为where urname=“111”, 如果传⼊的值是id,则解析成的sql为where urname=“id”. 
2、$将传⼊的数据直接显⽰⽣成在sql中。
如:where urname=${urname},如果传⼊的值是111,那么解析成sql时的值为where urname=111;
如果传⼊的值是;drop table ur;,则解析成的sql为:lect id, urname, password, role from ur where urname=;drop
table ur;
3、#⽅式能够很⼤程度防⽌sql注⼊,$⽅式⽆法防⽌Sql注⼊。
市场区
4、$⽅式⼀般⽤于传⼊数据库对象,例如传⼊表名.
5、⼀般能⽤#的就别⽤$,若不得不使⽤“${xxx}”这样的参数,要⼿⼯地做好过滤⼯作,来防⽌sql注⼊攻击。
6、在MyBatis中,“${xxx}”这样格式的参数会直接参与SQL编译,从⽽不能避免注⼊攻击。但涉及到动态表名和列名时,只能使
⽤“${xxx}”这样的参数格式。所以,这样的参数需要我们在代码中⼿⼯进⾏处理来防⽌注⼊。
【结论】在编写MyBatis的映射语句时,尽量采⽤“#{xxx}”这样的格式。若不得不使⽤“${xxx}”这样的参数,要⼿⼯地做好过滤⼯作,来防⽌SQL注⼊攻击。
mybatis是如何做到防⽌sql注⼊的
MyBatis框架作为⼀款半⾃动化的持久层框架,其SQL语句都要我们⾃⼰⼿动编写,这个时候当然需要防⽌SQL注⼊。其实,MyBatis的SQL是⼀个具有“输⼊+输出”的功能,类似于函数的结构,参考上⾯的两个例⼦。其中,parameterType表⽰了输⼊的参数类
型,resultType表⽰了输出的参数类型。回应上⽂,如果我们想防⽌SQL注⼊,理所当然地要在输⼊参数上下功夫。上⾯代码中使⽤#的即输⼊参数在SQL中拼接的部分,传⼊参数后,打印出执⾏的SQL语句,会看到SQL是这样的:
lect id, urname, password, role from ur where urname=? and password=?
不管输⼊什么参数,打印出的SQL都是这样的。这是因为MyBatis启⽤了预编译功能,在SQL执⾏前,会先将上⾯的SQL发送给数据库进⾏编译;执⾏时,直接使⽤编译好的SQL,替换占位符“?”就可以了。因为SQL注⼊只能对编译过程起作⽤,所以这样的⽅式就很好地避免了SQL注⼊的问题。
【底层实现原理】MyBatis是如何做到SQL预编译的呢?其实在框架底层,是JDBC中的PreparedStatement类在起作
⽤,PreparedStatement是我们很熟悉的Statement的⼦类,它的对象包含了编译好的SQL语句。这种“准备好”的⽅式不仅能提⾼安全性,⽽且在多次执⾏同⼀个SQL时,能够提⾼效率。原因是SQL已编译好,再次执⾏时⽆需再编译。
//安全的,预编译了的
Connection conn = getConn();//获得连接
String sql="lect id, urname, password, role from ur where id=?";//执⾏sql前会预编译号该条语句
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.tString(1, id);
ResultSet uteUpdate();
......
//不安全的,没进⾏预编译
private String getNameByUrId(String urId) {
Connection conn = getConn();//获得连接
String sql="lect id,urname,password,role from ur where id="+ id;
//当id参数为"3;drop table ur;"时,执⾏的sql语句如下:
//lect id,urname,password,role from ur where id=3; drop table ur;
PreparedStatement pstmt =  conn.prepareStatement(sql);
ResultSet uteUpdate();
......
}
干瞪眼的玩法简单说,#{}是经过预编译的,是安全的;${}是未经过预编译的,仅仅是取变量的值,是⾮安全的,存在SQL注⼊PreparedStatement的优点
1.Statement 需要进⾏字符串拼接,可读性和维护性⽐较差
String sql="inrt into hero values(null,"+"'提莫'"+","+313.0f+","+50+")";
PreparedStatement 使⽤参数设置,可读性好,不易犯错
String sql="inrt into hero values(null,?,?,?)";
2.PreparedStatement有预编译机制,性能⽐Statement更快
3.防⽌SQL注⼊式攻击
假设name是⽤户提交来的数据
String name ="'盖伦' OR 1=1";
使⽤Statement就需要进⾏字符串拼接
单人跳绳比赛规则
拼接出来的语句是:
lect*from hero where name ='盖伦'OR1=1
因为有OR 1=1,这是恒成⽴的
那么就会把所有的英雄都查出来,⽽不只是盖伦序列是什么意思
如果Hero表⾥的数据是海量的,⽐如⼏百万条,把这个表⾥的数据全部查出来会让数据库负载变⾼,CPU100%,内存消耗光,响应变得极其缓慢
⽽PreparedStatement使⽤的是参数设置,就不会有这个问题
打印的SQL语句为:
lect*from hero where name ="'盖伦' OR 1=1";
>环保主题的手抄报

本文发布于:2023-07-20 08:42:01,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/1106560.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:编译   语句   参数   数据   拼接   数据库   攻击
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图