[HN Gopher] Show HN: Execute JavaScript in a WebAssembly QuickJS...
___________________________________________________________________
Show HN: Execute JavaScript in a WebAssembly QuickJS sandbox
This TypeScript package allows you to safely execute JavaScript
code within a WebAssembly sandbox using the QuickJS engine. Perfect
for isolating and running untrusted code securely, it leverages the
lightweight and fast QuickJS engine compiled to WebAssembly,
providing a robust environment for code execution. Features -
*Security*: Run untrusted JavaScript code in a safe, isolated
environment. - *File System*: Can mount a virtual file system -
*Custom Node Modules*: Custom node modules are mountable - *Fetch
Client*: Can provide a fetch client to make http(s) calls - *Test-
Runner*: Includes a test runner and chai based `expect` -
*Performance*: Benefit from the lightweight and efficient QuickJS
engine. - *Versatility*: Easily integrate with existing TypeScript
projects. - *Simplicity*: User-friendly API for executing and
managing JavaScript code in the sandbox.
Author : sebastianwessel
Score : 129 points
Date : 2024-07-07 11:37 UTC (11 hours ago)
(HTM) web link (github.com)
(TXT) w3m dump (github.com)
| bluelightning2k wrote:
| Oh very nice! Guessing there isn't support for node modules but
| still very cool.
| brigadier132 wrote:
| Very cool. Since this is compiled to wasm can this run in the
| browser? It would be interesting if it could and still make fetch
| requests without attaching cookies to the request.
| revskill wrote:
| Does it support browser ?
| dualogy wrote:
| Pick one of the wasm runtimes written in JS listed at
| https://github.com/appcypher/awesome-wasm-runtimes and find out
| =)
| jojobas wrote:
| I thought the whole purpose of WebAssembly was _not_ to execute
| any JavaScript.
| mirekrusin wrote:
| Too late, he didn't know.
| brigadier132 wrote:
| Well you'd be mistaken. The point of WebAssembly is to run any
| language that compiles to WebAssembly in a secure sandbox.
| anon115 wrote:
| moew meoew moewm meow moew meow XDD the point of wasm is to
| play video games on the browser.
| jitl wrote:
| Hi, I'm the author of the underlying quickjs-emscripten runtime
| library. I like your ergonomic kind of "standard library" for
| quickjs-emscripten :)
|
| Did you try running in the browser or with a bundler? I think
| accepting the variant name as a string you pass to
| import(variantName) dynamically may not play well with Webpack et
| al.
|
| EDIT: SECURITY WARNING: this library exposes the ability for the
| guest (untrusted) code to `fetch` with the same cookies as the
| host `fetch` function. You must not run untrusted code if
| enabling `fetch`. Library should come with a big blinking warning
| about what is safe and unsafe to enable when running untrusted
| code. It's not a "sandbox" if the sandboxed code can call
| arbitrary HTTP APIs authenticated as the host context!
|
| The reason quickjs-emscripten is low-level and avoids magic is so
| I can confidently claim that the APIs it does provide _are_
| secure. I generally reject feature requests for magical
| serialization or easy network /filesystem access because that
| kind of code is a rich area for security mistakes. When you run
| untrusted code, you should carefully audit the sandbox itself,
| but also audit all the code you write to expose APIs to the
| sandbox.
|
| In this case a comment from an other HN user asking about Fetch
| cookies tipped me off to the potential security issue.
|
| More reading:
|
| Figma blog posts on plugin sandbox security:
|
| - https://www.figma.com/blog/how-we-built-the-figma-plugin-sys...
|
| - https://www.figma.com/blog/an-update-on-plugin-security/
|
| Quickjs-emscripten README: https://github.com/justjake/quickjs-
| emscripten
| jitl wrote:
| i wouldn't say "performance" as an advantage of running JS in
| QuickJS. QuickJS isn't competitive at all with the host JS VM,
| although I guess it's faster than older C interpreters, or an
| interpreter implemented in JavaScript.
| math_dandy wrote:
| I suppose you get performance benefits if the the time it takes
| to start up a nodejs process dominates the execution time of
| the script. This is probably the case for a decent proportion
| of "serverless function" type scripts.
| jitl wrote:
| This library expects to run inside a Javascript runtime like
| NodeJS, so you're always going to pay for the enclosing
| Javascript runtime to start.
| ijustlovemath wrote:
| Not true, QuickJS works completely standalone. I've used it
| to compile NodeJS libraries into standalone libraries that
| other C libraries can call, even on a system without a
| NodeJS install.
| anonymousd3vil wrote:
| so we come to a full circle
| TheRealPomax wrote:
| Spiral. Not circle. Having something run in itself is as old as
| the need to safely run something in order to see if it's going
| to blow up or not, though. If people aren't trying to write
| things so your general use programming environment can
| virtualize itself, it's basically not used seriously enough
| yet.
| degurechaff wrote:
| now we just need wasm intepreter in js. so we can run this
| package to run javascript to run wasm intepreter and so on..
| emurlin wrote:
| Interesting approach! As an author of another JS sandbox
| library[1] that uses workers for isolation plus some JS
| environment sanitisation techniques, I think that interpreting JS
| (so, JS-in-JS, or as in this case, JS-in-WASM) gives you the
| highest level of isolation, and also doesn't directly expose you
| to bugs in the host JS virtual machine itself. Since you're
| targeting Node, this is perhaps even more important because (some
| newer developments notwithstanding) Node.js doesn't really seem
| to have been designed with isolation and sandboxing in mind
| (unlike, say, Deno).
|
| From the API, I don't see if `createRuntime` allows you to define
| calls to the host environment (other than for `fetch`). This
| would be quite a useful feature, especially because you could use
| it to restrict communication with the outside world in a
| controlled way, without it being an all-or-nothing proposition.
|
| Likewise, it doesn't seem to support the browser (at least,
| running a quick check with esm.sh). I think that that could be a
| useful feature too.
|
| I'll run some tests as I'm curious what the overhead is in this
| case, but like I said, this sounds like a pretty solid approach.
|
| [1] @exact-realty/lot
| jitl wrote:
| I'm the author of the underlying quickjs-emscripten library. It
| supports the browser (specifically tested with ESM.sh), as well
| as Cloudflare Workers, NodeJS, Deno:
| https://github.com/justjake/quickjs-emscripten?tab=readme-ov...
|
| It has APIs for exposing host functions, calling guest
| functions, custom module loaders, etc:
| https://github.com/justjake/quickjs-emscripten?tab=readme-ov...
|
| API docs for newFunction: https://github.com/justjake/quickjs-
| emscripten/blob/main/doc...
| brigadier132 wrote:
| Wow cloudflare workers support is actually super cool. How
| does it limit memory usage?
| jitl wrote:
| The quickjs interpreter C code counts the bytes it's
| allocated, and refuses to allocate more if over the limit.
| It decrements by the allocation size when freed. This
| malloc function is used everywhere the interpreter
| allocates memory: static void
| *js_def_malloc(JSMallocState *s, size_t size) {
| void *ptr; /* Do not allocate zero
| bytes: behavior is platform dependent */
| assert(size != 0); if
| (unlikely(s->malloc_size + size > s->malloc_limit))
| return NULL; ptr = malloc(size);
| if (!ptr) return NULL;
| s->malloc_count++; s->malloc_size +=
| js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
| return ptr; }
| jiripospisil wrote:
| See also https://bytecodealliance.org/articles/javy-hosted-
| project
| AlexErrant wrote:
| There are many ways to sandbox Javascript, both serverside and
| browser-side.
|
| Are there any ways to "sandbox" DOM access? I.e. give untrusted
| 3rd parties access to a DOM element in a predefined spot? AFAIK
| the only tech that allows for this is iframes, which are
| unfortunately heavy and slow. I'm writing an app that can host
| plugins, and unfortunately, I think giving plugins DOM access
| means they can now literally do literally _anything_.
| cxr wrote:
| The closest thing I know of is Allen Wirfs-Brock's jsmirrors
| prototype, but he never got to speccing out anything for DOM
| (and never really intended to as far as I know). Just
| capabilities for JS-the-programming-system.
|
| You could look at jsmirrors for inspiration and take a crack at
| some sort of "dommirrors" yourself, but it's big undertaking.
| (There's a roundabout way to go about using jsmirrors as-is to
| kind of achieve what you want, but it's not ergonomic.)
|
| That being said, giving access to the DOM, even
| mediated/simulated, is almost certainly not what you really
| want. Figure out what you _actually_ want to allow the other
| side to do, and then just give them a capability that lets them
| do it. (For example, to let them add a button somewhere, you
| might think you need to give them an anchor point (parent
| element) where they can insert it and let them use
| `document.createElement` to make the DOM node that they're
| going to put there. But you don't actually want that--for them
| to have access to `document.createElement`, etc. What you want
| is for them to have an add-button capability. So give them
| _that_ --go implement `addButton`.)
|
| Moar: <https://news.ycombinator.com/item?id=30703531#30706060>
|
| PS: don't listen to anyone who comes along and says that this
| is what CSP is for. It's not. (If we're being accurate, even
| for what CSP really is for, it's poorly designed, user-hostile
| junk and should never have been implemented or extended as far
| as it has been.) It's dangerous to depend on it.
| spankalee wrote:
| Salesforce does this with a combination of web components, with
| a patched up ShadowRoot so that code with a reference to the
| shadow root can't walk into the rest of the document, and a
| secure evaluator function related to SES (Secure EcmaScript) to
| limit the globals the untrusted script has access too.
|
| The secure evaluator is wild. I think this is the heart of it:
| https://github.com/Agoric/realms-shim/blob/v1.1.0/src/evalua...
|
| There's also an idea for isolated web components to solve this
| in the platform:
| https://github.com/WICG/webcomponents/issues/1002
| cxr wrote:
| You can also check out the discussion for Figma's earlier
| work on their plugin system, which is what inspired jitl
| (above) to create quickjs-emscripten. Previously:
|
| _How to build a plugin system on the web and also sleep well
| at night_. <https://news.ycombinator.com/item?id=20770105>
| 2019 August 22. 89 comments.
| m1el wrote:
| Salesforce sandboxing is too easy to escape. Last time I
| needed to implement some feature for Salesforce, I've
| encountered 4 different escapes. It was also horrible dev
| experience.
| waldrews wrote:
| Yes! Now, we just have to run this inside a browser, which will
| run inside a container, which will run inside a VM, which will
| run on an emulation layer...
| djaouen wrote:
| If you're on wasm, why not just use Elixir and be done with it?
| FpUser wrote:
| CPU got too fast so let's run interpreter inside interpreter.
| devwastaken wrote:
| You cannot throw things into wasm and call it safe. It is wholly
| irresponsible. You need to do the work to ensure it's safe to a
| theory and in practice.
| brigadier132 wrote:
| quickjs with wasm can be considered secure before different
| system apis are introduced
| owenpalmer wrote:
| This is an xkcd waiting to happen
___________________________________________________________________
(page generated 2024-07-07 23:00 UTC)