5

I'm looking at the alternative that can substitute the use of eval() and new Function() javascript techniques. I'm developing a solution build with javascript and the platform on which it is built (Salesforce) recently has announced they're introducing CSP (content security policy) that will block the use of eval(), and other unsafe functions.

My solution is using eval function to evaluate string expressions and do some other magic stuff. I'm looking for some alternative, ideally without writing my own parser.

As I have mentioned, I use eval to evaluate expressions. Expressions that should be to be supported are usually like:

  • String comparison eval("'something' == 'something'") // return true
  • Calculations eval("2 + 2 * 3)" // return 8
  • && and || support eval("1 == 1 && 'cat' == 'dog'") // return false
  • Conditional operators,
    • at least ternary eval("(1 == 2 ? 'dog' : 'cat')") // return "cat"
    • full if-else would be really great: eval("if(1 == 2) { 'dog' } else if (1 == 3) { 'dog' } else { 'nothing' }") // return "nothing"
  • Some basic Math class methods, e.g.: eval("Math.ceil(12.313)"); // return 13

Capabilities that would be really great to have

  • Inject variable new Function("var item = this; item.number = 10;", item); // item is variable defined outside of eval and I want to dynamically modify it within eval()
  • Inject function definition eval("invert('123')") // return 321, invert() is a function defined somewhere else

I'm looking for something that is:

  • Relatively close to Javascript syntax (but I would accept if it would be some different language that can be interpreted by some js library compliant with CSP)
  • Not too much dependent on other libraries
  • Can be loaded without node.js etc (standalone js library)
Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
Maciek Simm
  • 151
  • 1
  • 1
  • 2
  • Would this work? https://github.com/NeilFraser/JS-Interpreter – Robert Harvey Jun 29 '16 at 18:19
  • 1
    May I ask what your use case is? – Populus Jun 29 '16 at 18:22
  • 1
    Robert, thank you for that link, I'm looking at it and I'll try if it will not be blocked by CSP tomorrow. @Populus - As I wrote - the use of pure eval() will be blocked by Content Security Policy of the platform. I need something that will allow me to evaluate string expressions. – Maciek Simm Jun 29 '16 at 20:31
  • 2
    That's not a use case, that's an implementation you're actively pursuing, one that is full of security holes and SalesForce is blocking it for a very good reason. – Populus Jun 29 '16 at 21:13
  • 1
    @Populus, yes you're right. I'm looking for an alternative for the evil eval(). The use case is that in the application I'm building I need to be able to evaluate string expressions (I described few examples above). These expressions are used to execute some rules: if (string expression == true) -> execute a rule. I'm looking for a solution that can exectue on the client side (web browser), ideally without too much waiting time. – Maciek Simm Jun 30 '16 at 08:20

1 Answers1

5

What you are looking for is a simple expression language that can be evaluated from within ECMAScript (which is just another way of saying there exists an interpreter written in ECMAScript). Thankfully, such a language and interpreter already exists: Jexl.

Jexl is a simple ECMAScript expression language that features pretty much everything you listed:

  • unary and binary operators, mathematical, logical and string operations,
  • comparison operators,
  • a conditional operator, and
  • you can pass a context object whose properties can be accessed like global variables in the expression.

This last one is not exactly what you are asking about, because you were asking about accessing arbitrary ECMAScript identifiers, but it is arguably more safe: you can only access what is explicitly passed in. And if you really wanted to, you could pass in the context object { window: window } and then your expression has access to the global window object and can do every evil thing you never imagined.

It also has some features you didn't list:

  • collections with filter operations: listOfPeople[.name == "John"] will return a sub-array of listOfPeople with only those people whose name property is "John" and
  • transformation pipelines: "A;B;C"|lower|split(";") // => ["a", "b", "c"].

It sounds like this is exactly what you are looking for.

Jörg W Mittag
  • 101,921
  • 24
  • 218
  • 318