mybatis下的ognl注入分析
字数 1543 2025-08-29 08:30:24

MyBatis下的OGNL注入分析与利用

1. MyBatis简介

MyBatis是一款优秀的持久层框架,它简化了JDBC代码,解决了JDBC将结果集封装为Java对象的麻烦。主要特点包括:

  • 通过XML或注解方式配置SQL语句
  • 将Java对象和SQL语句进行映射
  • 自动执行SQL并将结果映射为Java对象

1.1 MyBatis核心组件

  1. mybatis-config.xml:核心配置文件,用于生成SqlSessionFactory
  2. SqlSessionFactory:生成SqlSession对象
  3. SqlSession:执行SQL并返回结果,类似于JDBC中的Connection
  4. Executor:底层对象,执行SQL语句
  5. MapperStatement:接收输入映射和输出映射

2. OGNL注入原理分析

2.1 OGNL表达式在MyBatis中的解析过程

MyBatis在处理SQL语句时,会对包含${}的表达式进行OGNL解析:

  1. 当SQL语句中包含${expression}时,MyBatis会提取expression部分
  2. 将提取的内容作为OGNL表达式执行
  3. 将执行结果替换到SQL语句中

2.2 关键代码分析

  1. DynamicSqlSource:处理包含${}和动态SQL节点的SQL语句
  2. TextSqlNode.apply():解析SQL文本中的表达式
  3. BindingTokenParser.handleToken():将${}中的内容作为OGNL表达式执行

2.3 漏洞触发流程

  1. 用户输入被传入apply方法
  2. parse方法提取${}中的内容
  3. handleToken方法将内容作为OGNL表达式执行
  4. 执行结果被拼接到SQL语句中

3. 利用场景分析

3.1 XML配置中的潜在风险

在XML映射文件中,如果直接使用${}表达式且未做过滤,可能导致OGNL注入:

<select id="findUser" parameterType="String" resultType="User">
    SELECT * FROM users WHERE name = '${name}'
</select>

如果攻击者传入${@java.lang.Runtime@getRuntime().exec("calc")}作为name参数,将导致命令执行。

3.2 防御措施的限制

开发者通常的防御方式:

  • 先解析表达式,再添加参数
  • 这种方式可以防止直接通过参数注入OGNL表达式

3.3 注解方式的利用

3.3.1 常规注解的问题

使用@Select等注解时,仍然是先解析再放入参数,无法直接利用:

@Select("SELECT * FROM users WHERE name = '${name}'")
User findUserByName(@Param("name") String name);

3.3.2 Provider注解的利用

@SelectProvider等Provider注解存在风险,因为它们是先传入参数再解析:

@SelectProvider(type = UserSqlBuilder.class, method = "buildGetUsersByName")
List<User> getUsersByName(String name);

class UserSqlBuilder {
    public String buildGetUsersByName(String name) {
        return "SELECT * FROM users WHERE name = '" + name + "'";
    }
}

这种模式下,如果攻击者控制name参数,可以注入OGNL表达式。

4. 漏洞利用方法

4.1 基本利用方式

${@java.lang.Runtime@getRuntime().exec("calc")}

4.2 绕过限制的技巧

  1. 使用字符串拼接:

    ${@java.lang.Runtime@getRuntime().exec("calc".toString())}
    
  2. 使用反射:

    ${@java.lang.Class@forName("java.lang.Runtime").getMethod("getRuntime").invoke(null).exec("calc")}
    

4.3 实际攻击场景

  1. 通过Provider注解注入
  2. 通过XML映射文件注入(需能控制XML内容)
  3. 通过动态SQL注入

5. 防御措施

5.1 最佳实践

  1. 避免使用${}:尽量使用#{}预编译方式
  2. 严格过滤输入:对用户输入进行严格校验
  3. 禁用危险功能:限制OGNL表达式的执行能力

5.2 代码层面的防御

  1. 使用预编译语句:

    <select id="findUser" parameterType="String" resultType="User">
        SELECT * FROM users WHERE name = #{name}
    </select>
    
  2. 对Provider注解进行安全处理:

    class UserSqlBuilder {
        public String buildGetUsersByName(String name) {
            // 对name进行过滤
            String filteredName = filter(name);
            return "SELECT * FROM users WHERE name = '" + filteredName + "'";
        }
    }
    

5.3 配置层面的防御

  1. 限制OGNL的执行权限
  2. 使用安全的MyBatis配置
  3. 定期更新MyBatis版本

6. 总结

MyBatis中的OGNL注入是一个严重的安全问题,特别是在使用动态SQL和Provider注解时风险更高。开发者应当:

  1. 充分了解MyBatis的安全机制
  2. 避免直接使用${}表达式
  3. 对用户输入进行严格过滤
  4. 定期进行安全审计

通过合理的安全措施,可以有效防止OGNL注入漏洞的发生。

MyBatis下的OGNL注入分析与利用 1. MyBatis简介 MyBatis是一款优秀的持久层框架,它简化了JDBC代码,解决了JDBC将结果集封装为Java对象的麻烦。主要特点包括: 通过XML或注解方式配置SQL语句 将Java对象和SQL语句进行映射 自动执行SQL并将结果映射为Java对象 1.1 MyBatis核心组件 mybatis-config.xml :核心配置文件,用于生成SqlSessionFactory SqlSessionFactory :生成SqlSession对象 SqlSession :执行SQL并返回结果,类似于JDBC中的Connection Executor :底层对象,执行SQL语句 MapperStatement :接收输入映射和输出映射 2. OGNL注入原理分析 2.1 OGNL表达式在MyBatis中的解析过程 MyBatis在处理SQL语句时,会对包含 ${} 的表达式进行OGNL解析: 当SQL语句中包含 ${expression} 时,MyBatis会提取expression部分 将提取的内容作为OGNL表达式执行 将执行结果替换到SQL语句中 2.2 关键代码分析 DynamicSqlSource :处理包含 ${} 和动态SQL节点的SQL语句 TextSqlNode.apply() :解析SQL文本中的表达式 BindingTokenParser.handleToken() :将 ${} 中的内容作为OGNL表达式执行 2.3 漏洞触发流程 用户输入被传入 apply 方法 parse 方法提取 ${} 中的内容 handleToken 方法将内容作为OGNL表达式执行 执行结果被拼接到SQL语句中 3. 利用场景分析 3.1 XML配置中的潜在风险 在XML映射文件中,如果直接使用 ${} 表达式且未做过滤,可能导致OGNL注入: 如果攻击者传入 ${@java.lang.Runtime@getRuntime().exec("calc")} 作为name参数,将导致命令执行。 3.2 防御措施的限制 开发者通常的防御方式: 先解析表达式,再添加参数 这种方式可以防止直接通过参数注入OGNL表达式 3.3 注解方式的利用 3.3.1 常规注解的问题 使用 @Select 等注解时,仍然是先解析再放入参数,无法直接利用: 3.3.2 Provider注解的利用 @SelectProvider 等Provider注解存在风险,因为它们是先传入参数再解析: 这种模式下,如果攻击者控制name参数,可以注入OGNL表达式。 4. 漏洞利用方法 4.1 基本利用方式 4.2 绕过限制的技巧 使用字符串拼接: 使用反射: 4.3 实际攻击场景 通过Provider注解注入 通过XML映射文件注入(需能控制XML内容) 通过动态SQL注入 5. 防御措施 5.1 最佳实践 避免使用 ${} :尽量使用 #{} 预编译方式 严格过滤输入 :对用户输入进行严格校验 禁用危险功能 :限制OGNL表达式的执行能力 5.2 代码层面的防御 使用预编译语句: 对Provider注解进行安全处理: 5.3 配置层面的防御 限制OGNL的执行权限 使用安全的MyBatis配置 定期更新MyBatis版本 6. 总结 MyBatis中的OGNL注入是一个严重的安全问题,特别是在使用动态SQL和Provider注解时风险更高。开发者应当: 充分了解MyBatis的安全机制 避免直接使用 ${} 表达式 对用户输入进行严格过滤 定期进行安全审计 通过合理的安全措施,可以有效防止OGNL注入漏洞的发生。