CodeQL 文档

表达式语言注入 (JEXL)

ID: java/jexl-expression-injection
Kind: path-problem
Security severity: 9.3
Severity: error
Precision: high
Tags:
   - security
   - external/cwe/cwe-094
Query suites:
   - java-code-scanning.qls
   - java-security-extended.qls
   - java-security-and-quality.qls

单击以在 CodeQL 存储库中查看查询

Java EXpression Language (JEXL) 是 Apache Commons JEXL 库提供的简单表达式语言。其语法接近 ECMAScript 和 shell 脚本的混合。该语言允许调用 JVM 中可用的方法。如果使用攻击者控制的数据构建 JEXL 表达式,然后对其进行评估,则攻击者可能会运行任意代码。

建议

通常建议避免在 JEXL 表达式中使用不受信任的输入。如果无法做到这一点,则应在沙盒中运行 JEXL 表达式,该沙盒仅允许访问明确允许的类。

示例

以下示例使用不受信任的数据来构建和运行 JEXL 表达式。

public void evaluate(Socket socket) throws IOException {
  try (BufferedReader reader = new BufferedReader(
        new InputStreamReader(socket.getInputStream()))) {
    
    String input = reader.readLine();
    JexlEngine jexl = new JexlBuilder().create();
    JexlExpression expression = jexl.createExpression(input);
    JexlContext context = new MapContext();
    expression.evaluate(context);
  }
}

下一个示例显示了如何在仅允许访问 java.lang.Math 类中的方法的沙盒中运行不受信任的 JEXL 表达式。该沙盒使用 Apache Commons JEXL 3 提供的 JexlSandbox 类实现。

public void evaluate(Socket socket) throws IOException {
  try (BufferedReader reader = new BufferedReader(
        new InputStreamReader(socket.getInputStream()))) {
    
    JexlSandbox onlyMath = new JexlSandbox(false);
    onlyMath.white("java.lang.Math");
    JexlEngine jexl = new JexlBuilder().sandbox(onlyMath).create();
      
    String input = reader.readLine();
    JexlExpression expression = jexl.createExpression(input);
    JexlContext context = new MapContext();
    expression.evaluate(context);
  }
}

下一个示例显示了实现沙盒的另一种方法。它使用 JexlUberspect 的自定义实现,该实现检查被调用者是否是允许类的实例。

public void evaluate(Socket socket) throws IOException {
  try (BufferedReader reader = new BufferedReader(
        new InputStreamReader(socket.getInputStream()))) {
    
    JexlUberspect sandbox = new JexlUberspectSandbox();
    JexlEngine jexl = new JexlBuilder().uberspect(sandbox).create();
      
    String input = reader.readLine();
    JexlExpression expression = jexl.createExpression(input);
    JexlContext context = new MapContext();
    expression.evaluate(context);
  }

  private static class JexlUberspectSandbox implements JexlUberspect {

    private static final List<String> ALLOWED_CLASSES =
              Arrays.asList("java.lang.Math", "java.util.Random");

    private final JexlUberspect uberspect = new JexlBuilder().create().getUberspect();

    private void checkAccess(Object obj) {
      if (!ALLOWED_CLASSES.contains(obj.getClass().getCanonicalName())) {
        throw new AccessControlException("Not allowed");
      }
    }

    @Override
    public JexlMethod getMethod(Object obj, String method, Object... args) {
      checkAccess(obj);
      return uberspect.getMethod(obj, method, args);
    }

    @Override
    public List<PropertyResolver> getResolvers(JexlOperator op, Object obj) {
      checkAccess(obj);
      return uberspect.getResolvers(op, obj);
    }

    @Override
    public void setClassLoader(ClassLoader loader) {
      uberspect.setClassLoader(loader);
    }

    @Override
    public int getVersion() {
      return uberspect.getVersion();
    }

    @Override
    public JexlMethod getConstructor(Object obj, Object... args) {
      checkAccess(obj);
      return uberspect.getConstructor(obj, args);
    }

    @Override
    public JexlPropertyGet getPropertyGet(Object obj, Object identifier) {
      checkAccess(obj);
      return uberspect.getPropertyGet(obj, identifier);
    }

    @Override
    public JexlPropertyGet getPropertyGet(List<PropertyResolver> resolvers, Object obj, Object identifier) {
      checkAccess(obj);
      return uberspect.getPropertyGet(resolvers, obj, identifier);
    }

    @Override
    public JexlPropertySet getPropertySet(Object obj, Object identifier, Object arg) {
      checkAccess(obj);
      return uberspect.getPropertySet(obj, identifier, arg);
    }

    @Override
    public JexlPropertySet getPropertySet(List<PropertyResolver> resolvers, Object obj, Object identifier, Object arg) {
      checkAccess(obj);
      return uberspect.getPropertySet(resolvers, obj, identifier, arg);
    }

    @Override
    public Iterator<?> getIterator(Object obj) {
      checkAccess(obj);
      return uberspect.getIterator(obj);
    }

    @Override
    public JexlArithmetic.Uberspect getArithmetic(JexlArithmetic arithmetic) {
      return uberspect.getArithmetic(arithmetic);
    } 
  }
}

参考

  • ©GitHub, Inc.
  • 条款
  • 隐私