What is the best easy way to securely embed Javascript (or another well-known scripting language) in Rust?

I'm currently working on a web backend in Rust (actix web), and one of the features that I need is to allow users to implement custom functionality with (untrusted) code that runs on the server. In the research that I've done, it seems like Javascript is the best way to do this¹, but I can't find any good documentation on doing this.

My requirements/wish list are as such:

  • Very Fast (I need to run a few thousand JS functions per second.)
  • Very Fast to compile²/load (It won't be possible to cache the already-compiled² objects because it could be several hours to days between subsequent runs of most of the JS functions. If I can export the compiled² JS as bytes to very quickly load later and store that in a database, that would be fine.)
  • Secure (Sandboxed from problematic system calls, with configurations, including at compile²-time.)
  • Resource constrained (I don't want my server(s) to start crashing if some JS code uses excessive RAM, or for them to get bogged down by excessive CPU usage, including at compile²-time).
  • Very simple API — If possible, I don't want to spend more than a few minutes looking at rustdoc/examples to figure it out, and this is the main issue I see with existing V8 bindings (Maybe I just haven't found the right documentation.).
  • For OS/platform support, just Linux optionally with easily-installable system libraries is fine, but if it works on other OSes too for development that's better. The other parts of this list are much more important. Just x86_64 support is fine.

What JS system best meets these requirements for use in Rust?

1: I am open to other well-known scripting languages, and Python is a better fit here given the target users, but I doubt that it is feasible to embed it securely without digging through the guts of CPython. I want to avoid any relatively unknown Rust-specific languages to alleviate any burden of my users having to learn a new language ­— very few of them will be programmers first.

2: I know that JS isn't traditionally a compiled language like Rust or even Java/C#, but it does generally run in a JIT so compilation takes place.

Sounds to me like you want WASM rather than Javascript:

  1. WASM has high quality interpreters and compilers available. For JS, I have no clue as I barely ever see it used outside of browser contexts.
  2. WASM is designed to be more secure than JS ever will be.
  3. WASM is pretty fast. JS code can have much more variable performance, both due to GC and because some syntactic constructs are more expensive than others while at the same time it's far from obvious which is which if you're not a JS compiler writer.
  4. WASM code can often run outside the browser, depending on its dependencies

I found myself pondering exactly that possibility of using WASM for this task as well. Mainly because, as you say, it would be a great to get a secure sand box to run those untrusted, user supplied, codes in.

All kind of language compile to WASM, from C upwards. Unfortunately, as far as I can tell Javascript may never be a language usable in a WASM sandbox on account of it being such a dynamic language, not really suitable for compiling to WASM like Rust or C. One would end up including a whole JS engine in WAS to run it. Performance would be terrible.

So the question then is, is their such a thing as a super simple language like Javascript that non-programmers could get into that can be compiled to WASM?

I found your four numbered points interesting:

Javascript has been huge outside the browser for many years now since the arrival of node.js. It's widely used for desktop apps, like Visual Studio Code. Chrome plus node.js wrapped up as the Electron framework. JS is even used in embedded systems: Esprunino: https://shop.espruino.com/, Jerry Script: https://jerryscript.net/

Hmm... which makes me think... Jerryscript is a minimalist JS run time for memory constrained systems. If one could compile Jerryscript to WASM one would have a JS runtime in a secure WASM sand box.

Since when has JS been insecure? JS runs in a very similar sand box.

Quite likely true. I have yet to make any comparisons on that.

And so does JS, as noted above. However I suspect JS will never run well under WASM.

What about Lua?

Lua is a nice simple "JS" like scripting language, often used to give programmable facilities to the users on of non-programmer users. I imagine it would be far easier to get a Lua runtime compiled to WASM. In fact it already done (at leas for Lua in the browser):


`

2 Likes

I'm thinking of the capability system that WASM will be implementing at some point in the future. Compared to that, pretty much everything used today is insecure, even though things like memory management are properly accounted for.
What that capability system will make you do is be very explicit about which resources your app is using, and thus it will be easier to audit an app for undesirable behavior. That's something I haven't seen outside of research contexts so far.

I'm not surprised. But I'll never see such alternatives because to me, voluntarily working with Javascript when better alternatives are available is like choosing to drive a Lada when you could just as easily be driving a Porsche Taycan or a Tesla Roadster 202x.

As for Lua, it is indeed designed to be an embeddable scripting language. But choosing WASM vs Lua is a matter of details in terms of what is needed, as I don't think that Lua has a WASM compiler at this moment.

I was just going to recommend Lua, since it was designed to be embedded from the get-go.

2 Likes

Ah, interesting. I had not heard of such a capability system for WASM being on the horizon. Sounds like a great idea.

As it stands, I see JS and WASM as just code that gets loaded, interpreted/JITed and run in much the same way. Both of them are running in similar sand boxes with no direct access to the underlying machine. I see nothing inherently more insecure about Javasscript in this respect that WASM.

But also, as it stands, JS has access to to a huge and ever growing array of API's which can raise security concerns. Where as WASM has nothing, only being able to tunnel I/O through Javascript. In that respect one might expect WASM to be more secure, but that is noting to do with JS as a language vs WASM.

Car analogies are always terrible. If you ever had the misfortune to have to drive an old Lada for a few months you would know this one is especially terrible.

As it happens, at this time, Rust and Javascript are my two languages of choice. They are favorites for polar opposite reasons, Rust is fanatical about type correctness, memory use correctness, etc. JS node.js) totally isn't. Some years ago JS took over, from C++, everything we do when I was surprised to find that JS is a pretty sophisticated language, performance was very good but development was a thousand times easier. At the time I seriously looked at Go which did not seem to offer much more in either performance or ease of development. Java similarly, with the extra downer of Oracle and it's insistence on OOP. I don't know any better alternatives than Rust and JS for our purposes.

I did not mean "choosing WASM vs Lua". What I mean was compiling a Lua interpreter/run-time to WASM, then using that to run the users Lua scripts.

The motivation for that suggestion being that Lua is a nice easy to use scripting language like JS but I have a feeling it would be much easier to get a Lua run time working in WASM that a JS one.

I personally would just go with lua and not use wasm at all. Especially the requirement to compile very quickly is a big problem with wasm, since it's just as slow as native compile.

Lua does have all the sandboxing functionality you need out of the box, and it's way more lightweight and easy to embed than JavaScript.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.