MyBatis单表查询——参数占位符${}和#{}SQL注入like查询

Posted 一言不合就撒娇

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis单表查询——参数占位符${}和#{}SQL注入like查询相关的知识,希望对你有一定的参考价值。

目录

前言: 

1、参数占位符:$和#

2、SQL注入

 3、$的优点

小结:$  VS  #:

4、like查询

 解决方案,使用MySQL的内置函数concat()来处理


前言: 

        以下文章,对于没有接触过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  #:

  1. $存在SQL注入的问题,而#不存在
  2. $直接替换,#是预处理

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-查询返回一行一列和占位符分析

mybatis 之 占位符#{} 和 ${}

MyBatis框架学习

Mybatis之占位符与拼接符

mybatis的占位符区别

SSM框架Mybatis笔记 --- MyBatis 中应用动态代理;#{}占位符与${}占位符;执行DML后返回主键值;UUID