MyBatis单表查询——参数占位符${}和#{}SQL注入like查询
Posted 一言不合就撒娇
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis单表查询——参数占位符${}和#{}SQL注入like查询相关的知识,希望对你有一定的参考价值。
目录
前言:
以下文章,对于没有接触过Mybatis的小伙伴来说,需要看完这篇文章才可以继续向下执行:http://t.csdn.cn/nGTFZ
其次,我们为了更好地观察出现的问题,可以在配置文件中,配置打印MyBatis的执行SQL:
# 配置打印 MyBatis 执行的 SQL
logging:
level:
com:
example:
demo: debug
1、参数占位符:$和#
我们在mapper的.xml文件中,进行数据库的SQL语句编写时,通常会使用$和#作为参数占位符,例如:
$:
接口:
Userinfo getById(@Param("id") Integer id);
UserMapper.xml中:
<select id="getUserById" resultType="com.example.demo.entity.Userinfo">
select* from userinfo where id = $id
</select>
#:
接口:
Userinfo getByName(@Param("username") String username);
UserMapper.xml中:
<select id="getByName" resultType="com.example.demo.entity.Userinfo">
select * from userinfo where username = #username
</select>
以上代码是没有问题,但如果当我们在.xml文件中,将$id改为#id,将#username改为$username时,我们来测试一下【测试使用的是伪代码】:
@SpringBootTest
class UserMapperTest
@Autowired
private UserMapper userMapper;
@Test
void getById()
Userinfo userinfo = userMapper.getById(1);
System.out.println("查询结果:" +userinfo);
@Test
void getByName()
Userinfo userinfo = userMapper.getByName("张三");
System.out.println("查询结果:" +userinfo);
测试结果:
id查询成功:
username查询失败:
从这里,其实就能看到,SQL语句是=张三,而我们在学习数据库操作时就知道,字符串类型的需要用双引号括起来~
我们来看看这里$和#到底是怎么查询的呢?
使用#作为参数占位符时, #是进行预编译处理,也就是说MyBatis在处理#时,会将SQL中的#替换为?号,如同JDBC一样,使用PreparedStatement的set方法来赋值。也就是说传过来的参数会用引号括起来,如同sql语句的:
select * from userinfo where id = '1';
结果:
使用$作为参数占位符时,$是进行直接替换,也就是说,MyBatis在处理$时,直接把$替换成变量的值,如同上图中直接是username = 张三,如同sql语句的:
$是直接替换,就会有懂得程序的人借用这个漏洞,乘虚而入——SQL注入
什么是SQL注入呢?
2、SQL注入
假设有一个登录页面【假设数据库中刚好只有一条数据,因为有的配置下,当数据有多条时,可以执行成功,当有的配置下则无法成功】,需要输入用户名和密码:
接口:
Userinfo login(@Param("username") String name, @Param("password") String password);
XML中:
<select id="login" resultType="com.example.demo.entity.Userinfo">
select * from userinfo where username = #username and password = $password
</select>
用户名咱们正常使用#,在密码这里,咱们做一点手脚:使用$参数占位符~
测试:
@Test
void login()
String name = "张三";
String password = " 'xx' or 1=1";
Userinfo userinfo = userMapper.login(name,password);
System.out.println("登陆状态:"+(userinfo==null?"失败":"成功"));
结果:
使用错误的密码居然登陆成功了,这种问题,如果放在实际生活中,大家想想,多恐怖啊!
咱们来看看他实际执行的SQL语句:
控制台,试试看:
为什么说需要一条数据呢?因为,如果有多条,我的这个案例会将多所有的信息全部输出,如下:
而我们的接收写的是一个对象,而不是用聚合去接收~
结论:用于查询的字段,尽量使用#预查询的方式
那$就没有优点了吗?
还是有的,如下:
3、$的优点
查询中,带有SQL关键字,需要使用$
使用#会报错:
接口:
List<Userinfo> sortAll(@Param("sort") String userinfo);
xml:
<select id="sortAll" resultType="com.example.demo.entity.Userinfo">
select * from userinfo order by id #sort
</select>
测试:
@Test
void sortAll()
String sort = "desc";
List<Userinfo> userinfos = userMapper.sortAll(sort);
System.out.println(userinfos);
结果:
相当于在控制台输入:
select * from userinfo order by id 'desc';
换成$再测试:
这样子查询,必须要求传输的值是可以穷举的【如同排序要么是asc,要么是desc】,在使用之前需要对传递的值进行安全性验证~
小结:$ VS #:
- $存在SQL注入的问题,而#不存在
- $直接替换,#是预处理
4、like查询
like查询在使用#时,会报错:
举例:
接口:
List<Userinfo> likename(@Param("username") String username);
xml:
<select id="likename" resultType="com.example.demo.entity.Userinfo">
select * from userinfo where username like "%#username%"
</select>
测试:
@Test
void likename()
String username = "a";
List<Userinfo> userinfos = userMapper.likename(username);
System.out.println(userinfos);
结果:
如同在控制台输入:
正确的控制台应该输入什么:
解决方案,使用mysql的内置函数concat()来处理
xml代码:
<select id="likename" resultType="com.example.demo.entity.Userinfo">
select * from userinfo where username like concat('%',#username,'%')
</select>
运行:
好啦,本期到这里结束 啦,咱们下期再见咯~
以上是关于MyBatis单表查询——参数占位符${}和#{}SQL注入like查询的主要内容,如果未能解决你的问题,请参考以下文章
阶段3 1.Mybatis_05.使用Mybatis完成CRUD_5 Mybatis的CRUD-查询返回一行一列和占位符分析
SSM框架Mybatis笔记 --- MyBatis 中应用动态代理;#{}占位符与${}占位符;执行DML后返回主键值;UUID