New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
So called "secure" sandbox isn't secure at all #2
Comments
FWIW you can do something like |
You can potentially detect synchronous calls from sandbox, but you can't detect asynchronous calls - |
Hi, this is already fixed and tested in the next unreleased version, but I am waiting for more feedback before releasing it. My solution to this: About async functions: Final note: Thx for the feedback! |
This is also susceptible to simple string manipulation. For example, this will run outside the sandbox:
because it closes the |
var allow = function(code) {
try {
eval('(function() {' + code + '})');
return true;
} catch (e) {
return false;
}
} |
@kolodny That would suffer from the same problem, would it not? |
@bd0 |
@kolodny |
Another solution would be checking the string before passing it to
|
@solkimicreb A depth check might help, but it's not foolproof. For example: |
Yeah, thanks for the example. It seems like the best option would be to leave only the Another thing I thought of is only allowing single expressions like: |
I will try to move the with outside of the string and post the new code here. |
Btw, for an src like P.S. I mentioned it briefly in the post, but just to not forget, |
I figured out to use This solves two issues: firstly the string manipulation mentioned by @bd0, secondly: the ability to use strict mode inside passed code mentioned by @IKoshelev. What are your opinions, do you think I am missing something? Thanks for all the comments so far, I will be away for the weekend but get back to this topic on Monday (: P.S. Thanks for the warning about the regexp literal. I will try to look for a solution that doesn't modify (freeze) global stuff if I can in the long term. |
@solkimicreb At first glance it seems like it would suffer from the same problem, but I'd have to see it in context with the rest of the library. Something like: |
You may be able to do something like new Function('src', `return function(sandbox) { with (sandbox) { return eval(src) }}`)(src); But you may want to make eval a local function that nulls itself after it's first invocation, since there's no way to hide that in the executing scope |
@solkimicreb I've found something that seems to work, and is similar to @kolodny's suggestion. It's not perfect. The src has to be evaluated every time and I'm sure there are other issues I haven't thought of, but you don't have to worry about string manipulation. function has(target, key) {
// Only let eval execute once!
if (key === 'eval' && 0 === this.evaled++) {
return false;
}
return true;
}
function get(target, key, receiver) {
if (key === Symbol.unscopables) {
return undefined;
}
return Reflect.get(target, key, receiver)
}
function compileCode(src) {
// Return a function that wraps the given data
// in a proxy and executes the src.
return (function (dataObj) {
var dataProxy = new Proxy(dataObj, {
has,
get,
// Track # of times eval() has been called.
evaled: 0
});
// Set the src property on the proxy so it
// is accessible inside the with scope.
dataProxy.src = src;
// Evaluate the src inside the scope.
with(dataProxy) {
return eval(src);
}
});
}
var data = {
a: 1,
b: 2
};
var code = compileCode('"a is " + a + ", location is " + location;');
// Should print "a is 1, location is undefined"
console.log(code(data));
// Test for eval escalation. Can't allow eval to execute
// because it will gain access to the global scope.
var code2 = compileCode('eval.call(this, "window.location")');
try {
// Should throw an exception.
code2({});
}
catch(te) {
console.log(te);
} |
Hi! This is a proposal for nx-compile 2.0. I used all your amazing feedback to fix and test things. The biggest changes:
Thanks @bd0 , @kolodny ,@IKoshelev ! (P.S.: @bd0 I played around with your solution a lot. I also think moving the |
@solkimicreb Yeah, eval is weird. Another quirk I found was that assigning eval to another variable, e.g. |
You don't need to use eval to protect against string manipulation. You can just check if the given code is valid by itself, before compiling it into your special function: // Tests for syntax errors without running the code
new Function('"use strict"; ' + src);
// If the above operation didn't throw a syntax error, the operation below is safe
var code = new Function('sandbox', 'with (sandbox) {return (function () {"use strict"; ' + src + '}).call(this)}'); Using this method has three advantages:
|
Yeah, it seems like a nice solution, I will think about using it thanks (: |
Yes, in cases where each compiled code is only executed once, its performance will suffer. It's certainly more optimized for code that will be executed many times. As for your second concern, I've only ever seen two forms of string manipulation attacks:
Luckily, the second type of string manipulation is a non-issue for us, since we're not using string matching to check for dangerous code. |
@JoshuaWise After all the feedback and tests I think your pre-compiling solution is the way to go. Thanks for the idea! |
@JoshuaWise @kolodny @bd0 @IKoshelev I would like to add you to the contributors list. Let me know if you would like to be not included in it. Thx for all the feedback and ideas so far! |
I am going to close this now as all the issues mentioned here are fixed in the merged v2.0.0 of nx-compile. |
compileCode('return function(){}.constructor("alert(this)")()')({})
The text was updated successfully, but these errors were encountered: