背景:我正在开发一个框架/库,用于与greasemonkey / userscripts协调的特定网站。该框架/库将允许插件支持。它的工作方式是在库中添加一个插件寄存器,列出所需的页面,资源,ectera,库将等到满足所有的critera以调用addon的load()
函数。
问题:在这个“必需的东西”列表中,我希望addon devs能够指定javascript(作为字符串)作为“必需资源”进行评估。例如'document.getElementById("banana")'
。我想要做的是半沙盒评估“必需资源”,以便评估可以访问窗口& DOM对象但无法直接更改它们。我也想制作eval,并且沙盒中无法访问evalJS。
的实施例:
document.getElementById("banana")
- >有效document.getElementById("apple).id = "orange"
- >无效window.grape
- >有效window.grape = 'potato'
- >无效(someObj.applesCount > 0 ? 'some' : 'none')
- >有效
到目前为止我有什么:
function safeEval(input) {
// Remove eval and evalJS from the window:
var e = [window.eval, window.evalJS], a;
window.eval = function(){};
window.evalJS = function(){};
try {
/* More sanition needed before being passed to eval */
// Eval the input, stuffed into an annonomous function
// so the code to be evalued can not access the stored
// eval functions:
a = (e[0])("(function(){return "+input+"}())");
} catch(ex){}
// Return eval and evalJS to the window:
window.eval = e[0];
window.evalJS = e[1];
// Return the eval'd result
return a;
}
备注:
这是Greasemonkey / userscript。我没有直接访问权限来改变网站,或者是javascript
safeEval()
的输入可以是任何有效的javascript,无论是DOM查询还是简单的评估,只要它不会改变窗口对象或DOM。
答案 0 :(得分:5)
没有绝对的方法可以阻止最终用户或插件开发人员在JavaScript中执行特定代码。这就是为什么像JavaScript这样的开源语言中的安全措施被认为是万无一失的(因为它只对傻瓜有效)。
尽管如此,让我们构建一个沙盒安全层,以防止没有经验的开发人员破坏您的网站。我个人更喜欢使用Function
构造函数而不是eval
来执行用户代码,原因如下:
jQuery
)。this
指针并创建名为window
和document
的局部变量,以防止访问全局范围和DOM。这允许您创建自己的DOM版本并将其传递给用户代码。但请注意,即使是这种模式也有缺点。最重要的是,它可能只会阻止直接访问全球范围。用户代码仍然可以通过简单地声明没有var
的变量来创建全局变量,恶意代码可能会使用诸如创建函数之类的黑客并使用它的this
指针来访问全局范围(JavaScript的默认行为)。
让我们看看一些代码:http://jsfiddle.net/C3Kw7/
答案 1 :(得分:0)
如果您只想要一个简单的吸气剂,请编程一个而不是试图评估任何东西。
function get(input) {
// if input is a string, it will be used as a DOM selector
// if it is an array (of strings), they will access properties of the global object
if (typeof input == "string")
return document.querySelector(input);
else if (Array.isArray(input)) {
var res = window;
for (var i=0; i<input.length && typeof input[i] == "string" && res; i++)
res = res[input[i]];
return res;
}
return null;
}
答案 2 :(得分:0)
您可以执行以下操作:http://jsfiddle.net/g68NP/
问题是你必须添加大量代码来保护每个属性,每个本机方法等等。代码的内容实际上归结为使用__defineGetter__
,其支持是有限的。既然你可能没有在IE上运行它,你应该没问题。
编辑:http://jsfiddle.net/g68NP/1/此代码将使所有属性都是只读的。使用hasOwnProperty()
可能是也可能不合适。
如果JSFiddle失败:
function safeEval(input) {
// Remove eval and evalJS from the window:
var e = [window.eval, window.evalJS, document.getElementById], a;
window.eval = function(){};
window.evalJS = function(){};
document.getElementById = function (id) {
var elem = (e[2]).call(document, id);
for (var prop in elem) {
if (elem.hasOwnProperty(prop)) {
elem.__defineGetter__(prop, function () {
return (function (val) {
return val;
}(elem[prop]));
});
}
}
return elem;
};
try {
/* More sanition needed before being passed to eval */
// Eval the input, stuffed into an annonomous function
// so the code to be evalued can not access the stored
// eval functions:
a = (e[0])("(function(){return " + input + "}())");
} catch(ex){}
// Return eval and evalJS to the window:
window.eval = e[0];
window.evalJS = e[1];
document.getElementById = e[2];
// Return the eval'd result
return a;
}
答案 3 :(得分:0)
我知道这是一篇旧帖子,但我只是想分享 Aadit M Shah 解决方案的升级版本,这似乎真的是沙盒而无法访问窗口(或窗口子窗口) :http://jsfiddle.net/C3Kw7/20/
// create our own local versions of window and document with limited functionality
var locals = {
window: {
},
document: {
}
};
var that = Object.create(null); // create our own this object for the user code
var code = document.querySelector("textarea").value; // get the user code
var sandbox = createSandbox(code, that, locals); // create a sandbox
sandbox(); // call the user code in the sandbox
function createSandbox(code, that, locals) {
code = '"use strict";' + code;
var params = []; // the names of local variables
var args = []; // the local variables
var keys = Object.getOwnPropertyNames( window ),
value;
for( var i = 0; i < keys.length; ++i ) {
//console.log(keys[i]);
locals[keys[i]] = null;
}
delete locals['eval'];
delete locals['arguments'];
locals['alert'] = window.alert; // enable alert to be used
for (var param in locals) {
if (locals.hasOwnProperty(param)) {
args.push(locals[param]);
params.push(param);
}
}
var context = Array.prototype.concat.call(that, params, code); // create the parameter list for the sandbox
//console.log(context);
var sandbox = new (Function.prototype.bind.apply(Function, context)); // create the sandbox function
context = Array.prototype.concat.call(that, args); // create the argument list for the sandbox
return Function.prototype.bind.apply(sandbox, context); // bind the local variables to the sandbox
}