You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何限制Spring SpEL表达式范围以避免代码注入风险?

限制Spring SpEL执行范围,避免恶意注入

要实现仅允许从对象取值、阻断方法调用/反射等危险操作,核心是使用SimpleEvaluationContext替代默认的StandardEvaluationContext——它是Spring专门为安全场景设计的轻量级上下文,默认限制了方法调用、反射访问等风险操作,只支持属性访问和简单表达式运算。

具体实现步骤

1. 用SimpleEvaluationContext替代StandardEvaluationContext

把你的代码改成如下形式,使用只读数据绑定模式的SimpleEvaluationContext:

Test test = new Test("XYZ", 999);
ExpressionParser expressionParser = new SpelExpressionParser();
// 创建只读上下文,仅允许属性访问和简单比较/运算
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();

// 允许的表达式:访问属性并做比较
Expression allowedExpr = expressionParser.parseExpression("value eq 'XYZ'");
System.out.println(allowedExpr.getValue(context, test)); // 输出true

// 危险表达式会被拦截:尝试调用方法将抛出异常
Expression forbiddenExpr = expressionParser.parseExpression("''.getClass().forName('java.lang.Runtime').getMethods()[6]");
try {
    forbiddenExpr.getValue(context, test);
} catch (EvaluationException e) {
    System.out.println("危险表达式被拦截:" + e.getMessage());
}

2. 细粒度控制允许访问的属性

如果需要进一步限制只能访问特定属性,可以自定义PropertyAccessor,仅开放指定属性:

class RestrictedPropertyAccessor implements PropertyAccessor {
    // 仅允许访问以下属性
    private final Set<String> allowedProperties = Set.of("value", "number");

    @Override
    public Class<?>[] getSpecificTargetClasses() {
        return new Class[]{Test.class};
    }

    @Override
    public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
        return allowedProperties.contains(name);
    }

    @Override
    public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
        if (!canRead(context, target, name)) {
            throw new AccessException("属性 " + name + " 不允许访问");
        }
        try {
            Field field = Test.class.getDeclaredField(name);
            field.setAccessible(true);
            return new TypedValue(field.get(target));
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new AccessException("无法访问属性 " + name, e);
        }
    }

    @Override
    public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
        return false; // 禁止修改属性
    }

    @Override
    public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
        throw new AccessException("禁止修改属性");
    }
}

然后将自定义Accessor添加到上下文:

EvaluationContext context = SimpleEvaluationContext.builder()
        .withPropertyAccessors(new RestrictedPropertyAccessor())
        .build();

此时尝试访问非允许属性会直接抛出异常。

关键说明

  • SimpleEvaluationContext的forReadOnlyDataBinding()模式默认禁止方法调用、构造器调用、反射访问,仅支持属性访问、算术/比较运算等安全操作。
  • 绝对不要在不可信表达式场景下使用StandardEvaluationContext,它默认无任何限制,极易被恶意利用。

内容的提问来源于stack exchange,提问作者woytech

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 23:00:17