I want to give the user the possibility of writing symbolic maths formulas which are later evaluated with certain values.
The user might - for example - want to enter some formula a * (b + 1)
where a
and b
may be different upon each evaluation. My approach so far was using the built in JavaScript engine in Java but as I read through this tutorial on scripting, I realized that the engine is actually really powerful.
The formulas are stored in configuration files, so someone might send such a configuration file to another user, which would then be executed on their machine. Unfortunately I don't know JavaScript, so I don't know if the user could actually inject any seriously malicious code.
The formula above would be stored as a JavaScriptFormulaProcessor
object like this:
JavaScriptFormulaProcessor processor =
new JavaScriptFormulaProcessor("a * (b + 1)", "a", "b");
Initializing the engine:
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;
}
Executing the function:
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..
}
}
Does this code create an attack vector for my application? Bonus question: if yes, any better suggestions?
If formula
is under the users' control, then this code is extremely vulnerable because Java methods can be accessed and run from within the ScriptEngine
.
See also this question: Why can you execute Java-Code from a JS-ScriptEngine eval(String)?
As an example, consider this formula:
String formula = "(java.lang.Runtime.getRuntime().exec('some-malicious-script'), a+b)";
Apart from calculating the sum, this script would run java.lang.Runtime.getRuntime().exec()
.
You can run any static Java method this way.