Fork me on GitHub

#{}与${}的区别

PreparedStatement不允许在插入参数时改变SQL语句的逻辑结构。

为什么它这样处理就能预防SQL注入提高安全性呢?其实是因为SQL语句在程序运行前已经进行了预编译,在程序运行时第一次操作数据库之前,SQL语句已经被数据库分析,编译和优化,对应的执行计划也会缓存下来并允许数据库已参数化的形式进行查询,当运行时动态地把参数传给PreprareStatement时,即使参数里有敏感字符如 or '1=1'也数据库会作为一个参数一个字段的属性值来处理而不会作为一个SQL指令,如此,就起到了防止SQL注入的作用了!

经常碰到这样的面试题目:#{}和${}的区别是什么?

网上的答案是:
#{}是预编译处理,$ {}是字符串替换。
mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值,使用 #{} 可以有效的防止SQL注入,提高系统安全性。
mybatis在处理 $ { } 时,就是把 ${ } 替换成变量的值。
 
对于这个题目我感觉要抓住几点:
(1)#{}是预编译处理,MyBatis在处理#{ }时,它会将sql中的#{ }替换为?,然后调用PreparedStatement的set方法来赋值,传入字符串后,会在值两边加上单引号,如上面的值 “4,44,514”就会变成“ ‘4,44,514’ ”;
(2)预编译的机制。预编译是提前对SQL语句进行预编译,而其后注入的参数将不会再进行SQL编译。我们知道,SQL注入是发生在编译的过程中,因为恶意注入了某些特殊字符,最后被编译成了恶意的执行操作。而预编译机制则可以很好的防止SQL注入。
(3)是字符串替换,在处理是字符串替换,MyBatis在处理时,它会将sql中的{ }替换为变量的值,传入的数据不会加两边加上单引号
  1. ${param}传递的参数会被当成sql语句中的一部分,比如传递表名,字段名
  2. 例子:(传入值为id)
  3. order by ${param}
  4. 则解析成的sql为:order by id
    而使用${}在动态解析时候,会传入参数字符串
    select * from student where student_name = 'lyrics'
  1. #{parm}传入的数据都当成一个字符串,会对自动传入的数据加一个双引号
  2. 例子:(传入值为id)
  3. select * from table where name = #{param}
  4. 则解析成的sql为:
  5. select * from table where name = "id"
    select * from student where student_name = #{name} 
    预编译后,会动态解析成一个参数标记符?:
    select * from student where student_name = ?
 
  1. #{} 这种取值是编译好SQL语句再取值
  2. ${} 这种是取值以后再去编译SQL语句
为了安全,能用#的地方就用#方式传参,这样可以有效的防止sql注入攻击。
MyBatis排序时使用order by 动态参数时需要注意,用$而不是#,$一般用入传入数据库对象,比如数据库表名;
 

sql注入简介

直接上了百度的例子,感觉一看就清晰明了
某个网站的登录验证的SQL查询代码为:
strSQL = "SELECT * FROM users WHERE (name = '" + userName + "') and (pw = '"+ passWord +"');"
恶意填入
userName = "1' OR '1'='1";
与passWord = "1' OR '1'='1";
时,将导致原本的SQL字符串被填为
strSQL = "SELECT * FROM users WHERE (name = '1' OR '1'='1') and (pw = '1' OR '1'='1');"
也就是实际上运行的SQL命令会变成下面这样的
strSQL = "SELECT * FROM users;"
这样在后台帐号验证的时候巧妙地绕过了检验,达到无账号密码,亦可登录网站。所以SQL注入攻击被俗称为黑客的填空游戏。
 
 
posted @ 2020-05-30 19:55  威威超酷  阅读(836)  评论(0编辑  收藏  举报