Ebean框架常见SQL注入场景
字数 1445 2025-08-07 00:34:58
Ebean框架SQL注入安全指南
1. Ebean框架概述
Ebean是一个ORM框架,几乎支持所有JPA功能同时兼顾Mybatis的灵活性,具有以下特点:
- 支持类型约束的安全SQL语句构建
- 兼容多种数据库
- 提供实用的增强功能
- 对SQL注入有一定防护机制
1.1 基本使用方法
1.1.1 实体类操作
实体类继承Model类,自带增删改方法:
Author author = new Author(null, "Lorin", "Lorin");
author.save(); // 新增记录
1.1.2 查询接口
高版本已弃用Ebean/EbeanServer,迁移到:
io.ebean.Databaseio.bean.DB
1.1.3 Q实体增强类
Ebean会为实体类生成对应的Q类(如Author → QAuthor),功能更强大且操作有返回值:
QAuthor().id.eq(1).findOne(); // 查询id=1的记录
1.2 参数绑定方式
1.2.1 位置参数和命名参数
支持?和:param两种方式:
// 使用?位置参数
Ebean.createSqlQuery(sql).setParameter(1, name).findList();
// 使用:param命名参数
Ebean.createSqlQuery(sql).setParameter("paramName", value).findList();
1.2.2 表达式处理
Ebean表达式已进行预编译处理:
server.find(Content.class).where().eq("name", sort).findList();
2. 常见SQL注入场景
2.1 OrderBy排序注入
风险点:OrderBy无法预编译,直接拼接存在注入风险
危险接口:
io.ebean.OrderByasc(String propertyName)desc(String propertyName)
io.ebean.Queryorder(String var1)
io.ebean.ExpressionListorderBy(String var1)
危险示例:
server.find(Content.class).order(sort).findList(); // sort参数直接拼接
攻击示例:
攻击者可通过构造恶意sort参数进行报错注入获取数据库信息(如获取SA用户)
2.2 执行任意SQL、函数和存储过程
Raw表达式
虽然支持预编译,但直接拼接仍存在风险:
.raw("add_days(orderDate, 10) < ?", someDate) // 安全用法
.raw("add_days(orderDate, 10) < " + someDate) // 危险用法
rawOrEmpty()方法同理需要注意
2.3 执行自定义SQL
2.3.1 直接获取Connection执行SQL
通过事务获取Connection后直接执行SQL存在风险:
try (Transaction transaction = server.beginTransaction()) {
Connection connection = transaction.getConnection();
Statement stmt = connection.prepareStatement(sql); // 如果sql包含用户输入且未过滤
transaction.commit();
} catch (SQLException e) {
e.printStackTrace();
}
2.3.2 常见危险API
以下API如果直接拼接SQL且未过滤,存在注入风险:
createSqlQuery(String sql)sqlQuery(String var1)sqlUpdate(String var1)createCallableSql(String var1)createSqlUpdate(String sql)findNative(Class<T> var1, String var2)
安全示例:
String sql = "select id,name from customer where name like ?";
Customer customer = DB.findNative(Customer.class, sql)
.setParameter("Jo%")
.findOne();
2.3.3 RawSqlBuilder
直接拼接用户输入存在风险:
String sql = "SELECT v.id, c.company, c.postcode \n" +
"FROM venue v \n" +
"JOIN contact c ON (c.id = v.id) \n" +
"WHERE REPLACE(c.postcode,LIKE '%" + q + "%' \n" +
"OR c.company LIKE '%" + query + "%'";
RawSql rawSql = RawSqlBuilder.unparsed(sql) // 直接拼接用户输入query
.columnMapping("v.id", "id")
.columnMapping("c.company", "contact.company")
.columnMapping("c.postcode", "contact.postcode")
.create();
2.4 动态列名注入
直接使用用户输入作为列名存在风险:
Content.find.query().select(sort).findSingleAttributeList(); // sort直接拼接
3. 安全防护建议
3.1 参数化查询
始终使用参数化查询:
- 使用
?位置参数 - 使用
:param命名参数
3.2 特殊场景防护
对于OrderBy排序:
-
白名单验证:
- 设置表名/列名白名单
- 输入不在白名单内则使用默认值
-
间接引用:
String safeSort; switch(userInput) { case "1": safeSort = "name"; break; case "2": safeSort = "date"; break; default: safeSort = "id"; }
对于动态SQL:
- 使用SDK进行输入检查
- 避免直接拼接用户输入
- 对必要拼接内容进行严格过滤
3.3 其他建议
- 最小权限原则:数据库账户使用最小必要权限
- 日志监控:记录所有SQL操作日志
- 定期安全审计:检查所有SQL构建点
4. 总结
Ebean框架虽然提供了一定的SQL注入防护,但在以下场景仍需特别注意:
- OrderBy排序场景
- 原始SQL执行场景
- 动态列名/表名场景
- 自定义函数/存储过程调用场景
安全开发的关键在于:
- 始终使用参数化查询
- 对必须拼接的场景进行严格过滤
- 采用白名单或间接引用机制
- 定期进行代码安全审计