应用安全系列之四十六:Expression Language Injection (EL注入)

1、EL注入简介

Expression Language Injection (EL注入)是一种安全漏洞,攻击者能够注入并执行恶意的EL表达式,导致服务器端代码执行、敏感信息泄露或服务拒绝等安全问题。在Java EE环境中,特别是使用JSP(JavaServer Pages)技术的应用程序中,EL用于简化页面逻辑处理和数据展示。如果未正确处理用户输入,攻击者可以通过构造恶意输入来执行任意代码或者访问敏感信息。

EL注入的工作原理类似于其他注入攻击:

1、应用程序接收用户输入

2、未经验证或转义就将用户输入作为EL表达式处理

3、服务器解析并执行这些表达式,可能导致恶意操作

2、攻击原理

2.1、EL 表达式的解析

在 buildConstraintViolationWithTemplate 中,${...} 是一种表达式语言(EL)语法,Hibernate Validator 默认会解析这些表达式。

如果用户输入的内容直接被嵌入到错误消息模板中,并且没有经过适当的清理或转义,攻击者可以通过构造恶意输入来执行任意 EL 表达式。

2.2、潜在风险

  1. 攻击者可以利用 EL 表达式访问系统对象(如环境变量、文件系统等),甚至执行任意代码。
  2. 这种漏洞可能导致信息泄露、权限提升或其他严重后果。

2.3、示例攻击

假设某个字段允许用户输入值,并且该值直接被插入到错误消息模板中:

@Overridepublic boolean isValid(String value, ConstraintValidatorContext context) {
   if (value == null || value.isEmpty()) {
        context.disableDefaultConstraintViolation(); 
        context.buildConstraintViolationWithTemplate("Invalid value: ${validatedValue}")               .addConstraintViolation();        
        return false;    
    }    
    return true;
}

如果用户输入如下内容:

${T(java.lang.Runtime).getRuntime().exec('rm -rf /')}

当 EL 表达式被解析时,这将尝试执行系统命令 rm -rf /,从而导致严重的安全问题。

3、Spring 中易导致EL注入的API

以下Spring框架中的API容易导致EL注入问题:

1、Spring Expression Language (SpEL)

  1. SpelExpressionParserEvaluationContext ConstraintValidatorContext 相关方法(如:buildConstraintViolationWithTemplate),这些类用于解析和评估Spring表达式语言(SpEL),如果开发者不谨慎处理用户输入,就可能存在注入风险。
  2. @Value 注解中使用SpEL表达式,在Spring配置类或组件中使用@Value注解时,如果值来源于不可信来源且包含SpEL表达式,则可能导致安全问题。

2、JSP EL表达式

在JSP页面中直接使用 ${userInput}

3、Spring MVC 视图层

Thymeleaf、FreeMarker等模板引擎中不安全的表达式处理Spring Boot默认支持Thymeleaf作为视图层技术,虽然Thymeleaf默认是安全的,但如果启用了不安全的特性或错误地配置了模板引擎,仍有可能导致类似的注入问题。

4、Spring Data查询

使用SpEL的 @Query 注解

4、EL注入的解决方案

为了避免这种攻击,可以采取以下措施:

1 禁用 EL 表达式解析
  • Hibernate Validator 允许通过配置禁用 EL 表达式的解析。这是最直接和推荐的方法。 
  • 设置系统属性 hibernate.validator.el.enabled 为 false
  • System.setProperty("hibernate.validator.el.enabled", "false");
  • 在 Spring Boot 应用中,通过 application.properties 配置:
spring.jpa.properties.hibernate.validator.el.enabled=false

2、避免直接使用用户输入作为模板内容

不要直接将用户输入嵌入到错误消息模板中。可以通过硬编码模板或对用户输入进行严格的验证和清理来避免问题。

@Overridepublic boolean isValid(String userInput, ConstraintValidatorContext context) { 
   if (!isValidLogic(userInput)) {        
        String safeMessage = "Invalid input"; // 使用固定的错误消息        
        context.disableDefaultConstraintViolation();
        context.buildConstraintViolationWithTemplate(safeMessage).addConstraintViolation();        return false;    
    }    
return true;
}

3、使用占位符而非 EL 表达式

  • 如果需要动态生成错误消息,可以使用占位符(如 {0}),并通过参数化的方式传递值,而不是依赖 EL 表达式。
@Overridepublic boolean isValid(String userInput, ConstraintValidatorContext context) {
    if (!isValidLogic(userInput)) {        
        context.disableDefaultConstraintViolation();
        context.buildConstraintViolationWithTemplate("Invalid input: {0}") 
              .addPropertyNode("fieldName").addConstraintViolation();        
        return false;    
    }    

    return true;
}

4、升级到最新版本 

    • 确保使用的 Hibernate Validator 和相关库是最新版本,因为较新的版本可能已经修复了已知的安全漏洞。

    5、输入验证与过滤

      • 对所有用户输入进行严格的验证。
      • 过滤或转义EL表达式特殊字符如 ${}, #, T(), new 等

      6、使用安全的API配置

        // 使用SimpleEvaluationContext代替StandardEvaluationContext
        
        EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();

        5、总结

        • 风险点
          • buildConstraintViolationWithTemplate 方法默认支持 EL 表达式解析,如果用户输入被直接嵌入到模板中,可能导致 EL 注入攻击。
        • 解决方案
          1. 禁用 EL 表达式解析(推荐)。
          2. 避免直接使用用户输入作为模板内容。
          3. 使用占位符或硬编码的错误消息。
          4. 升级到最新的 Hibernate Validator 版本。
          5. 输入验证与过滤
          6. 使用安全的API配置

        通过采取上述措施,可以有效防止 buildConstraintViolationWithTemplate 导致的 EL 注入攻击,确保应用程序的安全性。

        ### PyCharm 打开文件显示全的解决方案 当遇到PyCharm打开文件显示全的情况时,可以尝试以下几种方法来解决问题。 #### 方法一:清理缓存并重启IDE 有时IDE内部缓存可能导致文件加载异常。通过清除缓存再启动程序能够有效改善此状况。具体操作路径为`File -> Invalidate Caches / Restart...`,之后按照提示完成相应动作即可[^1]。 #### 方法二:调整编辑器字体设置 如果是因为字体原因造成的内容显示问题,则可以通过修改编辑区内的文字样式来进行修复。进入`Settings/Preferences | Editor | Font`选项卡内更改合适的字号大小以及启用抗锯齿功能等参数配置[^2]。 #### 方法三:检查项目结构配置 对于某些特定场景下的源码视图缺失现象,可能是由于当前工作空间未能正确识别全部模块所引起。此时应该核查Project Structure的Content Roots设定项是否涵盖了整个工程根目录;必要时可手动添加遗漏部分,并保存变更生效[^3]。 ```python # 示例代码用于展示如何获取当前项目的根路径,在实际应用中可根据需求调用该函数辅助排查问题 import os def get_project_root(): current_file = os.path.abspath(__file__) project_dir = os.path.dirname(current_file) while not os.path.exists(os.path.join(project_dir, '.idea')): parent_dir = os.path.dirname(project_dir) if parent_dir == project_dir: break project_dir = parent_dir return project_dir print(f"Current Project Root Directory is {get_project_root()}") ```
        评论
        添加红包

        请填写红包祝福语或标题

        红包个数最小为10个

        红包金额最低5元

        当前余额3.43前往充值 >
        需支付:10.00
        成就一亿技术人!
        领取后你会自动成为博主和红包主的粉丝 规则
        hope_wisdom
        发出的红包
        实付
        使用余额支付
        点击重新获取
        扫码支付
        钱包余额 0

        抵扣说明:

        1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
        2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

        余额充值