提问人:AdityaK01 提问时间:9/18/2023 更新时间:9/22/2023 访问量:117
SPEL 注入 使用 SPEL 的安全问题
SPEL Injection Security concerns for using SPEL
问:
我们计划在基于 SaaS 的产品中使用 SPEL 来执行条件表达式。我的要求是使用评估条件,用户可以使用变量、常量和标准函数编写条件表达式。到目前为止,我使用 SpelExpressionParser() 解析器来解析表达式,然后使用 StandardEvaluationContext() 创建上下文,然后使用 expression evaluate 来计算表达式。
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("(#Tag.matches('52.*') && #Name.toUpperCase().matches('DEF.*') ");
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("Tag", "57345");
context.setVariable("Name", "defg");
Boolean result = (Boolean) exp.getValue(context);
这适用于我的所有要求,但我的安全团队对使用 StandardEvaluationContext() 有顾虑。StandardEvaluationContext() 可用于 SpEL 注入,并可用于使用 Java RMI 的远程方法调用。以下是一些安全问题:
SpEL 注入攻击:https://0xn3va.gitbook.io/cheat-sheets/framework/spring/spel-injection
OSWASP 关于 EL 注入攻击的文章:https://owasp.org/www-community/vulnerabilities/Expression_Language_Injection
我们被要求使用 SimpleEvaluationContext(),在那里我看到了我不能使用标准 java 函数和用户定义函数的限制(可能我不清楚是否有办法使用它)。
我计划在我的代码中使用最新的 2.7.x 版本的 spring 框架和 Java 11。
有人可以指导我了解:
使用 StandardEvaluationContext() 的更安全方法,我可以禁用某些 Java 函数,如 RMI 和系统函数,以便我可以安全地在我们的产品中使用?
如果 SimpleEvaluationContext() 是要走的路,那么有人可以帮我使用标准函数和用户定义的函数吗?
答:
在了解一些细节后,您可以更改方法并避免在这种情况下使用,而是使用 Java Bean Validation 并创建一个自定义方法。SPEL
像这样的东西:
将注释声明为ValidatorValues
Target
TYPE
@Documented
@Constraint(validatedBy = ValidatorValuesImpl.class)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidatorValues {
String message() default "All good";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
创建一个 impl,您将在其中将条件检查到方法中,这里作为示例,我从注释中放置了您的案例,顺便说一句,该方法总是返回 true,因为我们将其用作isValid
value generator
constraint validator
public class ValidatorValuesImpl implements ConstraintValidator<ValidatorValues, Dataset> {
@Override
public void initialize(ValidatorValues constraintAnnotation) {
ConstraintValidator.super.initialize(constraintAnnotation);
}
@Override
public boolean isValid(Dataset value, ConstraintValidatorContext context) {
value.setPromotion((value.getAge() > 30) && (value.getAge() < 50));
//.... others conditions
return true;
}
}
数据集也来自注释示例,这里我设置了 at 字段,因为它是根据用户输入动态设置的。@JsonIgnore
promotion
@Data
@AllArgsConstructor
@NoArgsConstructor
@ValidatorValues
public class Dataset {
private String name;
private Integer age;
private String phone;
private String email;
@JsonIgnore
private Boolean promotion;
}
还有当请求到达后端时将使用它的控制器层:
@RestController
@RequestMapping("/endpoint")
public class DataSetController {
private final Validator validator;
public DataSetController(Validator validator) {
this.validator = validator;
}
@PostMapping("/test")
ResponseEntity<String> createDataset(@RequestBody @Valid Dataset eventRequestBody) {
validator.validate(eventRequestBody);
return ResponseEntity.ok("promotion: " + eventRequestBody.getPromotion().toString());
}
}
一些测试用例 postman 请求/响应:
- 如果年龄未通过验证:应返回促销:
false
- 如果年龄通过验证:应返回促销:
true
评论