1

I would like to allow our users to write string parsing logic in JavaScript, that would then be executed on the server.

Edit (more info):

  • Regex is not an option as they will need if, else, switch etc
  • I would like to avoid creating a custom language
  • The idea is if the user knows JS they can write custom logic

I have looked at Stopping Infinite Loops by CodePen where they generate an Abstract Syntax Tree using Esprima and then regenerate the JavaScript we use Escodegen. What worries me with that approach is that someone could still introduce some kind of Unicode hack.

John Doherty
  • 3,669
  • 36
  • 38
  • Your best bet would be to use `new Function() { arg1, arg2, arg3, code )(arg1, arg2, arg3)`. This creates an isolated scope (except for global scope, which could be overwritten by adding local variables referring to global scope). You might want to place some safeguards on the code part (like disallowing `require` statements). If the code should return something, then you can catch the outcome – Icepickle Oct 11 '18 at 08:14
  • Executing client JS code on the server? Doesn't sound good. Only if you parse the code and make sure only allowed functions are called, no dead-loops, etc. Not easy. – pumbo Oct 11 '18 at 08:20
  • It sounds like you need a sandbox. – stdob-- Oct 11 '18 at 08:23
  • 1
    Depends on how complicated the parsing logic can be, you can come up with your own syntax (with support of 'if', 'else', etc), which will be parsed and executed on the server-side – pumbo Oct 11 '18 at 08:26
  • might be a possible duplicate of [Execute JavaScript code stored as a string](https://stackoverflow.com/questions/939326/execute-javascript-code-stored-as-a-string) – Tiisetso Tjabane Oct 11 '18 at 08:32
  • Doesn't sound like a good idea at all. You will have hard time parsing it as valid JS and keeping secure from something like `(1).constructor.constructor('console.log("Hi")')()` . AngularJS tried to do this with expressions and there were security holes for a long time. I guess you intend to apply this code in production? Looks like sandboxing isn't an option then. I'd suggest to go with some query DSL, depending on what you parse. Check https://github.com/search?l=JavaScript&q=parse+dsl&type=Repositories or https://www.npmjs.com/search?q=parse+dsl for some ideas. – Estus Flask Oct 11 '18 at 09:17
  • Do you trust your users? – Bergi Oct 11 '18 at 09:44
  • @AlexM I agree, it goes against everything. I have looked at generating an Abstract Syntax Tree etc _(updated question with links)_. I did consider my own syntax, but it's another learning curve for the user - I'd much rather they can google the commands etc – John Doherty Oct 11 '18 at 10:52
  • @stdob I agree, a Sandbox does feel like the right approach. Maybe a separate node service that takes params and function code? – John Doherty Oct 11 '18 at 10:52
  • @Bergi although I do trust our users, it is possible their system could be compromised so it'a always best to assume the worst – John Doherty Oct 11 '18 at 10:52

2 Answers2

2

The safest way would be to create your own parser/interpreter for some subset of javascript (or any other scripting language), or your own domain-specific lang. It's a lot of work, but still much easier and more secure than maintaining a sandboxed javascript VM on the server and communicating with it.

georg
  • 211,518
  • 52
  • 313
  • 390
  • thanks for your answer. Yes I agree and that was my initial thought, but you're right, it's a lot of work so I thought it was best to ask the community first. Someone must have done this before – John Doherty Oct 11 '18 at 10:54
  • @JohnDoherty I guess there are many toy language interpreters, but which of them fits your specific requirements ("string parsing") we cannot tell. – Bergi Oct 11 '18 at 11:12
0

An idea:

  1. users write their custom functions on a webpage

  2. webpage fetches data from the server

  3. the custom function is applied on the data on client side

  4. results are sent back to the server (make sure the results are not compromised)

Eriks Klotins
  • 4,042
  • 1
  • 12
  • 26