将用户输入评估为 Java Java 中的脚本时的安全风险
Security risks when evaluating user input as JavaScript in Java
我想为用户提供编写符号数学公式的可能性,这些公式稍后会用特定值进行计算。
用户可能 - 例如 - 想要输入一些公式 a * (b + 1)
,其中 a
和 b
在每次评估时可能不同。到目前为止,我的方法是使用 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 方法。
我想为用户提供编写符号数学公式的可能性,这些公式稍后会用特定值进行计算。
用户可能 - 例如 - 想要输入一些公式 a * (b + 1)
,其中 a
和 b
在每次评估时可能不同。到目前为止,我的方法是使用 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 方法。