新人一看就懂: #{} 和 ${} 的区别?

追求适度,才能走向成功;人在顶峰,迈步就是下坡;身在低谷,抬足既是登高;弦,绷得太紧会断;人,思虑过度会疯;水至清无鱼,人至真无友,山至高无树;适度,不是中庸,而是一种明智的生活态度。

导读:本篇文章讲解 新人一看就懂: #{} 和 ${} 的区别?,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

目录

一、区别概述

1.1、主要区别:

1.2、细节上:

二、具体描述

2.1、预编辑处理 vs 直接替换

2.2、SQL  注入问题

2.2.1、引发 SQL 注入

2.2.2、SQL 注入分析

2.3、排序查询

2.4、like 查询

2.4.1、%{} 模糊查询

2.4.2、#{} 模糊查询

2.4.3、#{} 模糊查询问题分析


一、区别概述


1.1、主要区别:

1、#{} 是预编译处理,${} 是直接替换

2、${} 存在SQL注入的问题,而 #{} 不存在;

Ps:这也是面试主要考察的部分~

1.2、细节上:

1、${} 可以实现排序查询,#{} 不能实现排序查询。

2、${} 可以直接进行模糊查询(但不建议,存在 SQL 注入问题),#{} 不可以直接进行模糊查询,但可以通过  mysql 内置函数 concat() 实现模糊查询(不存在 SQL 注入问题)。

二、具体描述


2.1、预编辑处理 vs 直接替换

预编辑处理:是指 MyBatis 在处理 #{} 时,就是把 ${} 替换成了 ?号,使用 PreparedStatement 的 set 方法来赋值。也就是说 #{} 会把 {} 内的整体看成 value ,最后再给 value 加上单引号,重点强调引号内部是一个整体( #{} 不会发生 SQL 注入的根本原因)。

直接替换:是指 MyBatis 在处理 ${} 时,会把 ${} 替换成变量的值(不会加引号处理)。

2.2、SQL  注入问题

2.2.1、引发 SQL 注入

例如现在有一个登陆程序,需要输入正确的账户和密码才能登录,当使用了 SQL 注入就可以在不知道密码的情况下进行登录,如下

xml 文件如下:

    <select id="login" resultType="com.example.demo.entity.Userinfo">
        select * from userinfo where username = '${username}' and password = '${password}'
    </select>

接口如下:

    /**
     * 登录逻辑
     * @param username
     * @param password
     * @return
     */
    Userinfo login(@Param("username") String username,
                   @Param("password") String password);

测试方法如下:

    @Test
    void login() {
        String username = "admin";
        String password = "' or 1 = '1";
        Userinfo userinfo = userMapper.login(username, password);
        System.out.println("登录状态:" + (userinfo == null ? "失败" : "成功"));
    }

执行结果如下:

新人一看就懂: #{} 和 ${} 的区别?

2.2.2、SQL 注入分析

可以在运行结果的日志中看到,我们最后执行的SQL语句如下:

新人一看就懂: #{} 和 ${} 的区别?

在 MySQL 中 1 = ‘1’ 结果必然为 true,所以不难分析出,如上 SQL 一定会将这张表中的用户全部返回(即使账号都填写错了,照样返回,因为1 = ‘1’ 必然为 true );

使用 ${} 的注意事项:一定是可以穷举的值,在使用之前一定要对传递的值进行合法性验证(在Controller中通过穷举的方式验证安全性)。

2.3、排序查询

使用 ${} 可以实现排序查询,而 #{} 不可以实现排序查询,因为使用  #{} 查询时,如果传递的值为 String 就会加单引号,导致 sql 错误。

例如你期望的 sql 语句为:select * from userinfo order by id desc;

而 #{sort} 中传入的是一个 String 类型的值为 “desc”;

那么最终实际的 sql 语句为:select * from userinfo order by id ‘desc’;这必然是错误的~

2.4、like 查询

2.4.1、%{} 模糊查询

方式一:直接替换 
<select id="likeSelect" resultType="com.example.demo.entity.Userinfo">
    select * from userinfo where username like '%${key}%'
</select>


方式二:使用concat进行字符串拼接
<select id="likeSelect" resultType="com.example.demo.entity.Userinfo">
    select * from userinfo where username like concat('%', '${key}', '%')
</select>

Ps:虽然可以这样,但并不建议使用 %{} 进行模糊查询,因为存在 SQL 注入问题。

2.4.2、#{} 模糊查询

<select id="likeSelect" resultType="com.example.demo.entity.Userinfo">    
    select * from userinfo where username like concat('%', #{key}, '%')
</select>

2.4.3、#{} 模糊查询问题分析

你期望的 sql 语句:select * from user where username = ‘%abc%’;

然而当你使用 #{} 传入的参数会自带引号,于是就变成了:select * from user where username = ‘%’ abc ‘%’;

新人一看就懂: #{} 和 ${} 的区别?

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/130361.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!