我想让用户有可能编写符号数学公式,这些公式稍后会用某些值进行评估。
用户可能 - 例如 - 想要输入一些公式a * (b + 1)
,其中a
和b
在每次评估时可能会有所不同。到目前为止,我的方法是在Java中使用内置的JavaScript引擎,但在我阅读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..
}
}
此代码是否为我的应用程序创建了攻击媒介?奖金问题:如果是,还有更好的建议吗?
答案 0 :(得分:1)
我想说这段代码不安全,因为你允许引擎评估JavaScript。
我会做什么: 将配置文件发送到服务器,接收器从中获取配置文件。编写一个解析器服务器端,它只接受有效的公式并丢弃任何不是的东西,然后将它存储在某个地方(数据库/文件/其他)。然后发送一个100%安全的包,你在解析到接收器后自己做了。通过这种方式,您可以确保接收器获得的任何信息都是由您首先验证的。
注意:如果你这样做,你需要在javascript中编写某种转换器,将你的包转换为javascript - 公式,以便通过你在问题中提供的代码来评估它。您可以选择仅验证服务器端,然后只发送最初发送给接收方的用户自制软件包,尽管您自己在验证时会犯错误导致接收方仍然运行不安全的代码。
答案 1 :(得分:0)
如果formula
受用户控制,则此代码极易受攻击,因为可以从ScriptEngine
内部访问和运行Java方法。
另请参阅以下问题:Why can you execute Java-Code from a JS-ScriptEngine eval(String)?
作为示例,请考虑以下公式:
String formula = "(java.lang.Runtime.getRuntime().exec('some-malicious-script'), a+b)";
除了计算总和,此脚本还将运行java.lang.Runtime.getRuntime().exec()
。
您可以通过这种方式运行任何静态Java方法。