前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Ebean框架常见SQL注入场景

Ebean框架常见SQL注入场景

作者头像
亿人安全
发布2024-06-17 17:03:10
990
发布2024-06-17 17:03:10
举报
文章被收录于专栏:红蓝对抗红蓝对抗

Ebean是一个ORM框架,利用其可以快速构建有类型约束的安全的SQL语句。本文主要介绍该框架常见的SQL注入场景。給代码安全审计提供一定的思路。

0x01 关于Ebean

Ebean ORM框架,可以说几乎支持所有的JPA的功能同时也兼顾了Mybatis的灵活性,并且还有一些较实用的增加功能。同时兼容多种数据库,可以很方便的实现对应的sql操作,在一定程度上对SQL注入也有一定的防护。

1.1 Ebean基本使用方法

1.1.1 实体类继承Model类,自带增删改方法

例如新增记录:

代码语言:javascript
复制
Author author = new Author(null, "Lorin", "Lorin");
author.save();

1.1.2 Ebean/EbeanServer&DB/database

可以使用Ebean或 EbeanServer 来创建和执行查询。高版本已经弃用,会迁移到io.ebean.Database/io.bean.DB:

1.1.3 Q实体增强类

Ebean可以对对应的entity生成出”Q实体类“,比如Author就会生成出QAuthor类,相比于普通实体类,QAuthor类的功能更强大,而且相比于普通实体类,QAuthor类的增删改有返回值,可以用来判断操作是否成功,普通实体类的增删改没有返回值。

例如查询id=1的内容:

代码语言:javascript
复制
QAuthor().id.eq(1).findOne();

1.2 常见参数绑定方式

1.2.1 ?和:param

跟其他框架类似,均支持?和:param的方式进行参数绑定。

类似SqlQuery可以直接执行自定义SQL,可以通过setParameter()方法进行参数绑定(多参数时可以使用setParameters()方法)。

代码语言:javascript
复制
Ebean.createSqlQuery(sql).setParameter(1,name).findList();

查看具体的SQL日志,name参数已经进行预编译处理:

使用:param同理。

1.2.2 表达式自身处理

Ebean提供的表达式已经进行了相应的预编译处理,使用也比较方便,例如这里的eq,查询对应name的用户信息:

代码语言:javascript
复制
server.find(Content.class).where().eq("name",sort).findList();

查看对应的日志已经进行了参数绑定:

0x02 常见SQL注入场景

2.1 OrderBy排序

因为OrderBy场景下是没办法进行预编译处理的,跟所有常见的orm框架一样,如果没有做相应的处理的话是存在SQL注入风险的。

常见的接口有:

  • io.ebean.OrderBy
    • Query asc(String propertyName)
    • Query desc(String propertyName)
  • io.ebean.Query
    • Query order(String var1);
  • io.ebean.ExpressionList;
    • Query orderBy(String var1);

举个例子,例如下面的SQL,通过用户传入的sort参数进行排序,因为是直接SQL拼接的,会存在SQL注入风险:

代码语言:javascript
复制
server.find(Content.class).order(sort).findList();

这里尝试报错注入,成功获取到数据库用户SA(数据库是H2 database)

2.2 执行任意 SQL、函数和存储过程

在查询where子句中经常需要包含执行任意SQL、函数和存储过程的需求。因为这里存在大量的自定义sql场景,如果直接拼接的话会存在SQL注入的风险,所以在审计时可以重点关注,下面列举一些常见的function:

Raw expressions Raw表达式允许在查询的where子句中使用对应数据库的函数或表达式。例如: ```java .raw("add_days(orderDate, 10) < ?", someDate)

代码语言:javascript
复制

 这里使用?进行预编译处理了,如果直接进行SQL拼接的话会存在注入风险。

rawOrEmpty()同理。

2.3 执行自定义SQL

由于实际业务比较复杂,常规的function并不能很好的完成业务需要,同样的Ebean也提供了很多自定义SQL的方法:

2.3.1 获取java.sql.Connection对象执行原始SQL

java.sql.Connection对象可以从事务中返回,此时就可以直接调用对应的方法执行任意的sql,同样的如果使用不当存在sql拼接的话也会存在SQL注入的风险:

代码语言:javascript
复制
try (Transaction transaction = server.beginTransaction()) {

    Connection connection = transaction.getConnection();
    // use raw JDBC
    Statement stmt = connection .prepareStatement(sql);
    ......
    transaction.commit();
} catch (SQLException throwables) {
    throwables.printStackTrace();
}

2.3.2 Ebean常见API

通过下面的api可以直接生成对应的sql进行执行,如果相关的参数没有经过过滤或者类似?和:param预编译处理,直接进行拼接的话,是存在SQL注入风险的。

  • createSqlQuery(String sql)
  • sqlQuery(String var1);
  • sqlUpdate(String var1);
  • createCallableSql(String var1);
  • createSqlUpdate(String sql)
  • findNative(Class\ var1,String var2)
  • ......

例如如下例子,这里通过?进行预编译处理,然后再通过setParameter进行赋值,避免了SQL注入的风险:

代码语言:javascript
复制
String sql= "select id,name f rom customer where name like ?";
Customer customer = DB.findNative(Customer.class, sql)
    .setParameter("Jo%")
    .findOne();

如果直接使用字符串拼接的话(尤其是类似orderby排序、动态表名等场景),如果没有经过相关的过滤,会存在SQL注入的风险,在审计时可以重点关注下。

2.3.2 RawSqlBuilder

一般来说可以通过RawSql显式指定要执行的SQL语句,并将列显式映射到对应的属性。但是使用不当也会出现SQL注入的风险。

例如如下例子,通过用户输入的query进行sql拼接,会存在sql注入的风险:

代码语言:javascript
复制
public static List search(String query) {
    List matches = new ArrayList();
    try {

        String sql =    "SELECT  v.id, c.company, c.postcode \n" +
                        "F ROM    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)
            .columnMapping("v.id", "id")
            .columnMapping("c.company", "contact.company")
            .columnMapping("c.postcode", "contact.postcode")
            .create();

        Query eQ = Ebean.find(Venue.class);

        eQ.setRawSql(rawSql);

        matches = eQ.findList();
    }
    catch (Exception e) {
        Utils.eHandler("Venue.search(" + query + ")", e);
    }
    finally {
        return matches;
    }
}

正确的做饭还是需要通过?或者param:进行预编译处理,然后再通过setParameter进行赋值。

2.4 动态列名

在列名查询时,可能会需要用到相关的sql函数,例如将数据库表中的姓和名拼接起来,Ebean中对应的select表达式是满足这个需求的。

举个例子,这里直接从用户传递的参数传入column进行查询,但是实际上存在sql拼接是有SQL注入风险的:

代码语言:javascript
复制
Content.find.query().select(sort).findSingleAttributeList();

这里尝试报错注入,成功获取到数据库用户SA(数据库是H2 database):

0x03 其他

上述场景中绝大部分是因为方法使用不当导致注入,可以通过param:或者?进行预编译的方式来避免,类似Orderby排序、动态拼接的场景,可以参考如下方法进行安全加固:

  1. 在代码层使用白名单验证方式,如设置表名白名单,如果输入不再白名单范围内则设置为一个默认值如user;
  2. 在代码层使用间接引用方式,如限制用户输入只能为数字1、2,当输入1时映射到user,为2时映射到product,其他情况均映射到一个默认值例如product;
  3. 使用sdk对用户输入进行安全检查。

0x04 参考资料

https://ebean.io/docs/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 亿人安全 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0x01 关于Ebean
    • 1.1 Ebean基本使用方法
      • 1.1.1 实体类继承Model类,自带增删改方法
      • 1.1.2 Ebean/EbeanServer&DB/database
      • 1.1.3 Q实体增强类
    • 1.2 常见参数绑定方式
      • 1.2.1 ?和:param
      • 1.2.2 表达式自身处理
  • 0x02 常见SQL注入场景
    • 2.1 OrderBy排序
      • 2.2 执行任意 SQL、函数和存储过程
        • 2.3 执行自定义SQL
          • 2.3.1 获取java.sql.Connection对象执行原始SQL
          • 2.3.2 Ebean常见API
          • 2.3.2 RawSqlBuilder
        • 2.4 动态列名
        • 0x03 其他
        • 0x04 参考资料
        相关产品与服务
        数据库
        云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档