将用户输入评估为 Java Java 中的脚本时的安全风险

Security risks when evaluating user input as JavaScript in Java

我想为用户提供编写符号数学公式的可能性,这些公式稍后会用特定值进行计算。

用户可能 - 例如 - 想要输入一些公式 a * (b + 1),其中 ab 在每次评估时可能不同。到目前为止,我的方法是使用 Java 中内置的 Java 脚本引擎,但当我通读 this tutorial on scripting 时,我意识到该引擎实际上非常强大。

公式存储在配置文件中,因此有人可能会将这样的配置文件发送给另一个用户,然后在他们的机器上执行。 不幸的是,我不知道 JavaScript,所以我不知道用户是否真的可以注入任何严重的恶意代码。

上面的公式将存储为 JavaScriptFormulaProcessor 对象,如下所示:

JavaScriptFormulaProcessor processor =
        new JavaScriptFormulaProcessor("a * (b + 1)", "a", "b");

正在初始化引擎:

public JavaScriptFormulaProcessor(String formula, String... variableNames) throws ScriptException {
    ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
    StringBuilder builder = new StringBuilder(variableNames[0]);
    for (int i = 1; i < variableNames.length; i++) {
        builder.append(", ").append(variableNames[i]);
    }
    String script = "function f("+builder.toString()+") { return "+formula+"}";
    engine.eval(script);
    invocable = (Invocable) engine;
}

执行函数:

public void execute(Number[] functionInputs) throws ScriptException {
    try {
        Object result = invocable.invokeFunction("f", functionInputs);
        // process result..
    } catch (NoSuchMethodException e) {
        throw new RuntimeException(e); // should actually never be thrown..
    }
}

此代码是否会为我的应用程序创建攻击向量?奖金问题:如果是,有更好的建议吗?

我会说这段代码不安全,因为您允许 JavaScript 由引擎评估。

我会做什么: 将配置文件发送到服务器,接收方从服务器获取配置文件。编写一个只接受有效公式并丢弃任何无效公式的解析器服务器端,然后将其存储在某个地方(数据库/文件/其他)。然后将自己解析后100%安全的包发送给接收方。通过这种方式,您可以确保接收方收到的任何信息都首先由您验证。

注意:如果你这样做,你需要在 javascript 中编写某种转换器,将你的包转换为 javascript - 公式,以便它被代码评估你提出你的问题。您可以选择只验证服务器端,然后只将最初发送给接收方的用户制作的包发送给接收方,尽管您允许自己在验证时犯错误导致接收方仍然 运行 不安全代码。

如果 formula 在用户的控制之下,那么这段代码 极度脆弱 因为 Java 方法可以被访问并且 运行来自 ScriptEngine.

另见这个问题:

例如,考虑这个公式:

String formula = "(java.lang.Runtime.getRuntime().exec('some-malicious-script'), a+b)";

除了计算总和外,此脚本还会 运行 java.lang.Runtime.getRuntime().exec()。 您可以通过这种方式 运行 任何静态 Java 方法。