文章主要内容包括:1、java 持久层技术/框架简单介绍.2、不同场景/框架下易导致 SQL 注入的写法.3、如何避免和修复 SQL 注入.
简介
文章主要内容包括:
1、Java 持久层技术/框架简单介绍
2、不同场景/框架下易导致 SQL 注入的写法
3、如何避免和修复 SQL 注入
JDBC
介绍
JDBC:
1、全称 Java Database Connectivity
2、是 Java 访问数据库的 API,不依赖于特定数据库 ( database-independent )
3、所有 Java 持久层技术都基于 JDBC
说明
直接使用 JDBC 的场景,如果代码中存在拼接 SQL 语句,那么很有可能会产生注入,如
安全的写法是使用 参数化查询 ( parameterized queries ),即 SQL 语句中使用参数绑定( ? 占位符 ) 和 PreparedStatement,如:
还有一些情况,比如 order by、column name,不能使用参数绑定,此时需要手工过滤,如通常 order by 的字段名是有限的,因此可以使用白名单的方式来限制参数值
这里需要注意的是,使用了 PreparedStatement 并不意味着不会产生注入,如果在使用 PreparedStatement 之前,存在拼接 sql 语句,那么仍然会导致注入,如
正常情况下,用户的输入是作为参数值的,而在 SQL 注入中,用户的输入是作为 SQL 指令的一部分,会被数据库进行编译/解释执行。当使用了 PreparedStatement,带占位符 ( ? ) 的 sql 语句只会被编译一次,之后执行只是将占位符替换为用户输入,并不会再次编译/解释,因此从根本上防止了 SQL 注入问题。
更详细和准确的回答,请参考:
Mybatis
介绍
1、首个 class persistence framework
2、介于 JDBC (raw SQL) 和 Hibernate (ORM)
3、简化绝大部分 JDBC 代码、手工设置参数和获取结果
4、灵活,使用者能够完全控制 SQL,支持高级映射
说明
在 MyBatis 中,使用 XML 文件 或 Annotation 来进行配置和映射,将 interfaces 和 Java POJOs (Plain Old Java Objects) 映射到 database records
XML 例子
Mapper Interface
XML 配置文件
Annotation 例子
可以看到,使用者需要自己编写 SQL 语句,因此当使用不当时,会导致注入问题
与使用 JDBC 不同的是,MyBatis 使用 #{} 和 ${} 来进行参数值替换
使用 #{} 语法时,MyBatis 会自动生成 PreparedStatement ,使用参数绑定 ( ?) 的方式来设置值,上述两个例子等价的 JDBC 查询代码如下:
因此 #{} 可以有效防止 SQL 注入,详细可参考 http://www.mybatis.org/mybatis-3/sqlmap-xml.html String Substitution 部分
而使用 ${} 语法时,MyBatis 会直接注入原始字符串,即相当于拼接字符串,因而会导致 SQL 注入,如:
name 值为 ' or '1'='1,实际执行的语句为:
因此建议尽量使用 #{},但有些时候,如 order by 语句,使用 #{} 会导致出错,如:
sortBy 参数值为 name ,替换后会成为:
即以字符串 “name” 来排序,而非按照 name 字段排序,详细可参考 https://stackoverflow.com/a/32996866/6467552
这种情况就需要使用 ${}
使用了 ${}后,使用者需要自行过滤输入,方法有:
代码层使用白名单的方式,限制 sortBy 允许的值,如只能为 name, email 字段,异常情况则设置为默认值 name在 XML 配置文件中,使用 if 标签来进行判断
Mapper 接口方法
List<User> getUserListSortBy(@Param("sortBy") String sortBy);
xml 配置文件
因为 Mybatis 不支持 else,需要默认值的情况,可以使用 choose(when,otherwise)
更多场景
除了 orderby之外,还有一些可能会使用到 ${} 情况,可以使用其他方法避免,如:
like 语句
如需要使用通配符 ( wildcard characters % 和 _) ,可以在代码层,在参数值两边加上 %,然后再使用 #{} 使用 bind 标签来构造新参数,然后再使用 #{}
Mapper 接口方法
List getUserListLike(@Param("name") String name);
xml 配置文件
使用 SQL concat() 函数
除了注入问题之外,这里还需要对用户的输入进行过滤,不允许有通配符,否则在表中数据量较多的时候,假设用户输入为 %%,会进行全表模糊查询,严重情况下可导致 DOS
IN 条件
xml 配置文件
limit 语句
1、直接使用 #{} 即可
2、Mapper 接口方法
List<User> getUserListLimit(@Param("offset") int offset, @Param("limit") int limit);
xml 配置文件
JPA & Hibernate
介绍
JPA:
1、全称 Java Persistence API
2、ORM (object-relational mapping) 持久层 API,需要有具体的实现
Hibernate:
JPA ORM 实现
说明
这里有一种错误的认识,使用了 ORM 框架,就不会有 SQL 注入。而实际上,在 Hibernate 中,支持 HQL (Hibernate Query Language) 和 native sql 查询,前者存在 HQL 注入,后者和之前 JDBC 存在相同的注入问题,来具体看一下
HQL
HQL 查询例子
这里的 User 为类名,和原生 SQL 类似,拼接会导致注入
正确的用法:
位置参数 (Positional parameter)
命名参数 (named parameter)
命名参数 list (named parameter list)
类实例 (JavaBean)
Native SQL
存在 SQL 注入
使用参数绑定来设置参数值
JPA
JPA 中使用 JPQL (Java Persistence Query Language),同时也支持 native sql,因此和 Hibernate 存在类似的问题,这里就不再细说。
编程语言原本是被设计成专门使用在计算机上的,但它们也可以用来定义算法或者数据结构。正是因为如此,程序员才会试图使程序代码更容易阅读。
上一篇:编程语言 泛型快速入门教程
下一篇:编程语言的Istio分层架构
¥498.00
¥29.00
¥399.00
¥299.00