什么是 SQL 注入:
- SQL 注入是一种注入攻击,可以执行恶意 SQL 语句,它将任意 SQL 代码插入数据库查询,使攻击者能够完全控制 WEB 应用程序后面的数据库服务器,攻击者可以使用 SQL 注入漏洞绕过程序安全措施
- 可以绕过网页或 WEB 应用程序的身份验证和授权,并检索中整个 SQL 数据库的内容
- 还可以使用 SQL 注入来添加、修改和删除数据库中的记录
- 简单来说:
- SQL 注入是一种将 SQL 代码添加到输入参数中,传递到 SQL服务器解析并执行的一种攻击手法,传入参数未经过过滤,直接拼接到 SQL 语句中,解析执行,达到预先之外的行为
- SQL注入案例:
name = 'addss' and password = 1' or '1' = '1
SQL注入解决:
-
JDBC解决:
- 把 SQL 语句中需要传参的位置用 ?占位符给替换
- 更改 Statement 对象为 PreparedStatement对象:
//传入参数地方用占位符 ? 替换 select * from student where name = ? and password = ?//未改动前语句: Statement statement = (Statement) connection.createStatement();//更改 Statement 对象为 PreparedStatement //获取对象并编译sql PreparedStatement statement = (PreparedStatement) connection.prepareStatement(sql); //给占位符赋值 statement.setString(1, name); statement.setString(1, password);
- 解决方式:
- 使用 PreparedStatement 对象是先将 SQL 语句的骨架发送给服务器编译并确定下来,编译之后 SQL 语句的骨架和语义就不会再被改变了,再将 SQL 语句中的参数发送给服务器
- 即使参数中再包含 SQL 关键字或者特殊符号,也不会导致 SQL 语句的骨架或语义被改变,只会被当作普通的文本来处理
- 解决步骤:
- 使用 PreparedStatement 对象代替 Statement 对象传输 SQL 语句骨架,并返回一个 PreparedStatment 对象
PreparedStatement ops = oCn.preparedStatemnt(sql); //说明:一个 SQL 语句骨架指的是使用 ? (占位符) 代替自定义变量后的 SQL 语句示例:select * from user where name = ? and password = ?;该方法使用一个 PreparedStatement 对象值对应一条 SQL 语句骨架,想要使用其他 SQL 语句骨架就得重新创建一个该类的对象
- 使用 PreparedStatement 的类方法 setBaseType(占位符序号,变量名);构造实参,填充占位符
- SQL 骨架中有多少个 ?就得使用该类方法构造多少个实参
- 该类方法第一个实参指的是占位符的服啊后,序号是从 1 开始的,区别与下标
- 构造的实参必须与占位符的序号 一 一 对应
- 方法名中的 BaseType 指的是不同类型的数据要使用对应类型的 set 方法,如类型 int 数据,则使用 setInt 方法构造实参
- 将填充完的 SQL 语句传输给数据库:
oPs.executeQurey() 或 oPs.executeUpdate() 方法传输构造好的 SQL 语句
- 使用 PreparedStatement 对象代替 Statement 对象传输 SQL 语句骨架,并返回一个 PreparedStatment 对象
- 优点:
- 使用 PreparedStatement 对象可以防止 SQL 注入攻击
- 而且通过方法设置参数更加的方便且不易出错
- 还可以从某方面提高程序执行的效率
-
#{} 和 $ value} 符号:
- ${value}:数据拼接,在本地 SQL 语句进行拼接(会有 SQL 注入问题)
- #{}:占位符 ==> 被编译成占位符 ?
- 两者的选择:
- 能用 #{} 就用 #{},尽量少用 ${}
- 当数据作为参数,或者 order by 排序时用 ${}
- 传参时参数使用 @Param 注解,
- 正确的将参数传入 SQL 语句中,一般通过 #{} 的方式,${} 会有 SQL 注入的问题
- 原理:
- MyBatis 的 #{} 之所以能够预防 SQL 注入是因为底层使用了 PreparedStatment 类 setString() 方法来设置参数
- 此方法会获取参数传递过来的每个字符,然后进行循环对比,如果发现有敏感字符(如:单引号、双引号等),则会在上面加一个 '/' 代表转义符号,让其变成一个普通的字符串,不参与 SQL 语句的生成,达到预防 SQL 注入的效果