目录
缘由
最近在的一个项目上面,发现有人在给我搞 SQL 注入,我真的想说我那么点资源测试用的阿里云服务器,个人估计哈,估计能抗住他的请求
系统上面的截图
数据库的截图
说句实在的,看到这个之后我立马就是在想啊,现在我们都是用的成熟的ORM 框架,一般调用 ORM 框架的方法操作数据库是不会有问题的。
后面又让我想起来了,#{} 与 ${} 的区别,这里总结下,说一句通俗易懂的话:使用 #{} 可以防止SQL注入,使用 ${} 就会出现 SQL 注入。
代码理解
咱们都是程序员,都喜欢说,别给我说那么多废话,show me the code,那么我们直接看代码吧,我们通过伪代码来理解下:
public void test(String name, String id){ String sql = "update orders set name = "+name+" where id = ?"; }
这里我为了方便与说明,就是使用上面的一个SQL 来解析,从上面的 SQL 可以看到两点信息:
- name:是直接使用了拼接字符串的方式,这里就是类似于 ${} 做的事情
- id:使用了 ? 做为占位符,做了一次预处理,先去编译SQL,后面再来做参数化操作,这个是 #{} 的具体原理
如果是 name 被恶意传入了 SQL 代码,比如:
") OR (SELECT*FROM(SELECT(SLEEP(3)))hnao) limit 1# 或者" union select 1--
那么解析出来的 SQL 就会变成:
update orders set name = ) OR (SELECT*FROM(SELECT(SLEEP(3)))hnao) limit 1update orders set name = union select 1
虽然上面比较难看,因为我这里举例是 update,如果是查询呢:
select name from orders union select 1--
那这样子是不是就出问题了?其实只要他成功一次,那么就可能窃取到我们数据库的信息了。
#{} 与 ${} 的区别
这里我也去百度了下,然后整理一下大致的区别,在 MyBatis 中,#{} 和 ${} 都是用于在 SQL 语句中插入参数的占位符,但它们之间有着显著的区别。
预编译与安全性:
- #{}:这是一个预编译(PreparedStatement)的占位符。当 MyBatis 在解析 XML 映射文件或注解中的 SQL 时,它会为 #{} 中的参数生成一个 PreparedStatement,并使用 ? 作为占位符。这意味着 SQL 语句会被预编译,并且在执行时会使用参数化查询,这样可以防止 SQL 注入攻击。
- ${}:这是一个简单的字符串替换。MyBatis 会直接替换 ${} 中的内容为 SQL 语句中的相应部分。这意味着 SQL 语句不会被预编译,而是会动态地构建和执行。这可能会导致 SQL 注入攻击,因为它允许不受限制的字符串替换。
用法:
- #{}:通常用于插入参数值,例如列值、条件值等。
- ${}:通常用于插入 SQL 片段,如表名、列名、动态 SQL 语句等。
动态 SQL:
- 在 MyBatis 中,${} 更多地用于构建动态 SQL,因为它允许直接替换 SQL 语句中的任何部分。然而,由于这种灵活性,它也增加了 SQL 注入的风险。
- #{} 在动态 SQL 中通常用于插入参数值,以确保安全性。
类型处理器:
- 对于 #{} 插入的参数,MyBatis 会使用相应的类型处理器(Type Handler)来确保参数与数据库中的列类型匹配,并进行必要的类型转换。
- 而对于 ${},由于它直接替换 SQL 语句中的部分,因此不会使用类型处理器。
注意事项:
- 尽可能使用 #{} 来插入参数值,以确保 SQL 语句的安全性和性能。
- 如果确实需要使用 ${}(例如,插入表名或列名),请确保传入的字符串是安全的,并且不包含任何来自不受信任的来源的内容。
在使用动态 SQL 时,要特别注意 SQL 注入的风险,并采取相应的预防措施。
总之,#{} 和 ${} 在 MyBatis 中各有其用途,但 #{} 通常更安全、更可靠,并应优先使用。
发表回复
评论列表(0条)