JDBC
使用Statement执行查询语句的时候 :
比如要执行用户名 密码登录验证的sql语句 经常要输入 String sql = " select * from login where name=’ " +name+ " ’ and pwd = ’ " +pwd+ " ’ ";
这时候如果用户输入的密码是 ’ or ‘1’ = '1
这时候 整条输出语句可以拼装为 select * from login where name=‘xx’ and pwd =’ ’ or ‘1’ = ‘1’
因为 ‘1’ = ‘1’ 永远为true 相当于 select * from login; 会把表中所有数据都查出来 甚至可能进行修改、删除
而使用PreparedStatement 就可以防止sql注入方式 是因为 它进行了循环遍历:
首先这个类进行语句执行不是直接进行语句的拼接,而是先进行预编译,用? 进行占位 再set()的时候 将属性左右加上 ’ (int类型不会)
然后会把用户输入的所有字符集全部遍历 如果识别出 一些特殊字符 比如 换行符、\ 、双引号、单引号 还有一些特殊字符 会进行编译
比如还是输入刚才的密码 会变成 select * from login where name=‘xx’ and pwd =’ ’ or ‘1’ = ‘1’ ’
所以使用了PreparedStatement 就 无法截断SQL语句,也就是说 无法拼接SQL语句,防止了sql注入。
https://blog.csdn.net/qq_39740629/article/details/77719468
JDBC 的 PrepareStatement 可以阻止 SQL 注入攻击,MyBatis 之类的 ORM 框架也可以阻止 SQL 注入,如何实现的?
因为SQL语句在程序运行前已经进行了预编译,在程序运行时第一次操作数据库之前,SQL语句已经被数据库分析,编译和优化,对应的执行计划也会缓存下来并允许数据库已参数化的形式进行查询,当运行时动态地把参数传给PreprareStatement时,即使参数里有敏感字符如 or '1=1’也数据库会作为一个参数一个字段的属性值来处理而不会作为一个SQL指令,如此,就起到了SQL注入的作用了
如果用statement jdbc会简单拼接字符串然后作为sql执行
preparedstatement就会进行预编译 对其中的换行符等字符做转义 对注入的sql会起到混淆的作用
mybatis这些orm框架也是基于preparedstatement mybatis尽量使用#占位符
参考:https://blog.csdn.net/qililong88/article/details/105142570
1、SQL注入攻击:
由于dao中执行的SQL语句是拼接出来的,其中有一部分内容是由用户从客户端传入,所以当用户传入的数据中包含sql关键字时,就有可能通过这些关键字改变sql语句的语义,从而执行一些特殊的操作,这样的攻击方式就叫做sql注入攻击
PreparedStatement利用预编译的机制将sql语句的主干和参数分别传输给数据库服务器,从而使数据库分辨的出哪些是sql语句的主干哪些是参数,这样一来即使参数中带了sql的关键字,数据库服务器也仅仅将他当作参数值使用,关键字不会起作用,从而从原理上防止了sql注入的问题
PreparedStatement主要有如下的三个优点:
1.可以防止sql注入
2.由于使用了预编译机制,执行的效率要高于Statement
3.sql语句使用?形式替代参数,然后再用方法设置?的值,比起拼接字符串,代码更加优雅.
PreparedStatement 与Statment比较
- 语法不同:PreparedStatement可以使用预编译的sql,而Statment只能使用静态的sql
- 效率不同: PreparedStatement可以使用sql缓存区,效率比Statment高
- 安全性不同: PreparedStatement可以有效防止sql注入,而Statment不能防止sql注入。
https://www.cnblogs.com/flei/p/6727520.html
MyBatis
MyBatis中#和$的区别
与PreparedStatement类似,
#可以防止Sql 注入,它会将所有传入的参数作为一个字符串来处理。
$ 则将传入的参数拼接到Sql上去执行,一般用于表名和字段名参数,$ 所对应的参数应该由服务器端提供,前端可以用参数进行选择,避免 Sql 注入的风险。
https://blog.csdn.net/Activity_Time/article/details/96572671