Replies: 1 comment
-
|
Note for posterity: Here's pseudocode with notes on the main trick behind it in case it gets lost: const initOnce = `
// This is not the preferred way to make those available below, but easier to read as an illustration.
const FERAL_FUNCTION = Function;
const getOwnPropertyNames = Object.getOwnPropertyNames;
Object.preventExtensions(globalThis); // this seems to only work in Hermes out of all engines tested
lockdown(options);
getCompartmentEndowmentsAtRuntime = (id) => {
return { globals: {...}};
}
`
const before = `(function(){
const $k = [...new Set([...getOwnPropertyNames(globalThis), ...getOwnPropertyNames(this.globals)])];
return new FERAL_FUNCTION(
'{' + $k + '}',
String.raw\`;(function(){"use strict";
`
const after = `
})()\`).bind(null,this.globals)
}).call(getCompartmentEndowmentsAtRuntime(${someFormOfIdentification}))()`
const bundle = `${initOnce}; /*for each module:*/${before}${source}${after}` |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
This is a description for an alternate Compartment sandboxing approach relying on static analysis and code generation.
The generated code wraps the untrusted code and no transformation of the untrusted code is required.
This construction does not require a with-statement or a Proxy and is strict-mode compatible. Feral eval is optional and can be replaced with templating.
This approach may be useful when working in situations:
SES shim:
SES Sandboxing is composed from with-statement + proxy + eval
however:
SES Sandboxing shim uses the with-statement for both of its primary sandboxing tasks:
This approach:
The scope denial uses a Proxy in order to handle any possible uttered value. However if you have access to the code you can perform static analysis on it and as long as direct eval is not available, all potential utterances can be trivially known. Given a list of utterances you can prepare code to prevent them from accessing values in higher scopes.
The scope population of Compartment properties can be accomplished by creating variables in scope. The synchronization of values between the Compartment globalThis properties and the variables can be accomplished by using setters and getters on the globalThis. Only utterable properties need to be synchronized, un-utterable properties can be defined directly on the Compartment globalThis. While the untrused code would be able to modify the property descriptors on the Compartment globalThis, this would only reduce shim fidelity and not reduce security.
Endowments do not need to be known at the time of code generation. We don't need to distinguish between allowed and disallowed utterances.
Multiple evaluations in the same Compartment can be accomplished with some restrictions. In order to have a single Compartment globalThis object and have it correctly synchronize its properties with global variables, the evaluations must be evaluated within the same scope below the Compartment scope machinery.
Dynamic evaluations (requested at runtime, eg indirect eval) in the same compartment may be possible with some restrictions. Each evaluation may be unable to have utterances in common.⚠️ Further research required.
Limitations:
location = '(target url)'Beta Was this translation helpful? Give feedback.
All reactions