tc39 / proposal-shadowrealm

ECMAScript Proposal, specs, and reference implementation for Realms
https://tc39.es/proposal-shadowrealm/
1.41k stars 67 forks source link

Why not call it a Sandbox? #368

Closed devlato closed 2 years ago

devlato commented 2 years ago

Hey team!

Just wondering why not use the industry-standard name 'Sandbox' instead of 'Realm'?

kriskowal commented 2 years ago

It’s a neat name idea and I don’t remember it coming up in the Epic Name Bikeshed.

If the naming bikeshed were still open, while a realm is a sandbox, many other things are also sandboxes; the name does not indicate what distinguishes it from the others.

ljharb commented 2 years ago

That name has security implications that i suspect would be undesirable.

devlato commented 2 years ago

@ljharb on the other hand, the name "Realm" has implications in the way that you need to read several pages of documentation just to understand what's that about, yet the idea behind Realms isn't new to the industry

Jamesernator commented 2 years ago

@ljharb on the other hand, the name "Realm" has implications in the way that you need to read several pages of documentation just to understand what's that about, yet the idea behind Realms isn't new to the industry

The main reason for that is there never has been a standardized realm in the language, so it's been kind've smeared over things like vm.newContext in Node and iframe.contentWindow in browsers.

I don't think the idea that "a realm is a (fresh) set of builtin objects" is really a hard definition to grasp. Like it's no more abstract that how an "Array is a ordered collection of values", the fact that the specification of arrays is to do with a bunch of property descriptor and internal methods operators is umimportant to get the general idea.

Like the most descriptive name is definitely not "Sandbox", because it isn't really a sandbox, it really is just a fresh set of builtin objects with some methods to evaluate code with those builtin objects. Those builtin objects could very well contain things that are very much not safe, for example there's interest in Node to be able to import any builtin module into shadow realms, quite frankly I don't think access to the filesystem/child processes is what anyone would think of "Sandbox" as being.

devlato commented 2 years ago

@Jamesernator technically, if you can set custom any built-in objects, you can customize the environment in which the code is executed – practically, you can replace any APIs with your own stubs and this is pretty sandbox-ish 🤔

Jamesernator commented 2 years ago

@Jamesernator technically, if you can set custom any built-in objects, you can customize the environment in which the code is executed – practically, you can replace any APIs with your own stubs and this is pretty sandbox-ish

Yes, but ShadowRealm isn't creating the sandbox, you are. You might as well define:

class Sandbox {
    #shadowRealm = new ShadowRealm();

    constructor() {
        // clean the shadow realm of unsafe globals
    }
}

to declare a "Sandbox".

practically, you can replace any APIs with your own stubs and this is pretty sandbox-ish

Actually no, if Node does implement what I mentioned, then import("node:fs") would allow code in a ShadowRealm to gain access to fs regardless of what globals you delete or replace.

If you want actual sandboxing, you need both this proposal and at least minimum the compartments proposal. Even then you probably want the ses proposal if you're actually going to be running untrusted code.

mhofman commented 2 years ago

You can replace APIs in any realm, not just Shadow Realms (minus some host environments which expose some APIs as non-configurable in the principal realm, which is disallowed in ShadowRealm).

However in both there's one thing you cannot replace or prevent with current ecma262 mechanisms: dynamic imports. Because of that any realm, including a ShadowRealm, is not a sandbox, and uncensored code can potentially access powerful capabilities.

devlato commented 2 years ago

Actually no, if Node does implement https://github.com/nodejs/TSC/issues/1221, then import("node:fs") would allow code in a ShadowRealm to gain access to fs regardless of what globals you delete or replace.

Yeah but it's be a Node.js mechanism (with custom require impl) and not a part of the specification itself I guess? And nothing will prevent you from providing a custom require in the created Realm, that would forbid importing modules like this?

devlato commented 2 years ago

However in both there's one thing you cannot replace or prevent with current ecma262 mechanisms: dynamic imports. Because of that any realm, including a ShadowRealm, is not a sandbox, and uncensored code can potentially access powerful capabilities.

Hmmm okay – why not make it a real sandbox then? Or consider adding an (optional) import interceptor support that would allow the host to handle dynamic import requests coming from within the sandbox?

Jack-Works commented 2 years ago

Hmmm okay – why not make it a real sandbox then? Or consider adding an (optional) import interceptor support that would allow the host to handle dynamic import requests coming from within the sandbox?

That will be covered by the compartment proposal.

Jamesernator commented 2 years ago

Yeah but it's be a Node.js mechanism (with custom require impl) and not a part of the specification itself I guess?

Implementations are explictly allowed to add whatever they want to ShadowRealm, the point of ShadowRealm is that fresh builtins can be created whenever desired. Browsers will be adding all manner of APIs to ShadowRealm.

And nothing will prevent you from providing a custom require in the created Realm, that would forbid importing modules like this?

import() is not require(), Node has supported some form of ESM since at least v14 and import() cannot be affected by changing require.

Hmmm okay – why not make it a real sandbox then? Or consider adding an (optional) import interceptor support that would allow the host to handle dynamic import requests coming from within the sandbox?

The realm proposal used to be like this, however it was decided that ShadowRealm and Compartment could be split into separate parts that could be used either individually or together. For compartments in particular, there's a lot of interest in hooking behaviour without needing to create new globals.

devlato commented 2 years ago

Right. I'm asking because at my company, we've been creating plugin APIs and have to use iframes for sandboxing (which isn't the most convenient mechanism) – so an API that would practically, achieve a similar level of isolation and customization, would be extremely convenient

mhofman commented 2 years ago

plugin APIs [...] for sandboxing

I highly recommend you read @erights Taxonomy of Security Issues. There are a lot of attacks a simple new realm won't protect you against, for example timing based confidentiality attacks.

Depending on your use case, a frozen built-ins approach with some API taming might work. In particular you may be interested in the SES shim which implements the SES proposal (which we plan to update to reflect the latest work on compartments)

Jamesernator commented 2 years ago

so an API that would practically, achieve a similar level of isolation and customization, would be extremely convenient

Compartments are still an active proposal, one reason ShadowRealm is at stage 3 but compartments are still at stage 1 is because the realms proposal has gone through a lot of work to ensure it's something that engines can easily support.

So in previous versions of realms, they used to behave more like same-origin iframes and objects could be shared freely between parent and child realms. However there was skepticism that this design was actually in the best interests of both developers and engines, last year there was an idea for sync message passing which evolved a bit into the current design.

The history behind realms is actually very long, they were originally part of the ES6 draft, however they were removed at some point (I think due to lack of implemeter interest), and have been through various proposals over the years ever since. I'm not familiar with the entire history, but from the parts I've seen it could easily cover a very large blog post just to cover all the turns and changes.

Jamesernator commented 2 years ago

we've been creating plugin APIs and have to use iframes for sandboxing (which isn't the most convenient mechanism)

The article mentioned @mhofman is good, although I will point that a full sandbox is still not trivial to create even with realms, compartments and SES, but it is still significantly easier than prior given you won't need to literally reimplement those parts from scratch.

Unless you really know what you're doing, it's probably better to use a library that wraps these proposals to provide sandboxing. If you really need to roll your own, then you really need to understand all of the attack models in that article. (In particular note that even exposing something like Date.now to the untrusted code allows reading basically any memory in the page thanks to spectre).

jdalton commented 2 years ago

This conversation is leading nowhere and is not productive. The name stands.

leobalter commented 2 years ago

This proposal/API is not seeking for a new name anymore. Please refer to our previous discussions and threads over the - now resolved - name bikeshed.

devlato commented 1 year ago

@jdalton why so assertive? That's quite a weird attitude