假设我在全局范围内有一个变量。是否可以限制javascript函数的范围?
假设我想定义一个函数,我可以保证将无法访问这个变量,有没有一种方法来包装函数,或调用函数,这将确保这?
事实上,我需要任何预定功能具有明确定义的访问的变量,并且该接入被之前定义,并且从该函数定义独立。
动机: 我考虑的用户提交的功能的可能性。我应该能够相信这个功能是一些“安全”的功能,因此很高兴在我自己的网站上发布它们。
假设我在全局范围内有一个变量。是否可以限制javascript函数的范围?
假设我想定义一个函数,我可以保证将无法访问这个变量,有没有一种方法来包装函数,或调用函数,这将确保这?
事实上,我需要任何预定功能具有明确定义的访问的变量,并且该接入被之前定义,并且从该函数定义独立。
动机: 我考虑的用户提交的功能的可能性。我应该能够相信这个功能是一些“安全”的功能,因此很高兴在我自己的网站上发布它们。
运行在托管在不同产地的iframe
的代码。这是保证不可信代码被沙箱化并阻止访问全局变量或页面的DOM的唯一方法。
就像jsFiddle一样 - 我一定会期待他们对此进行研究并发现它是最好的选择。 –
这就是caja所做的; http://code.google.com/p/google-caja/ –
我打算至少给出一种可能性的技术答案。使用全球的名称作为参数传递给该函数:
someGlobal = 5;
function cantSeeThatGlobal(someGlobal) {
console.log(someGlobal);
}
cantSeeThatGlobal(); // prints undefined
cantSeeThatGlobal(10); // prints 10
这将是当然的只是为了更好地不使用全局变量如初。
我不相信会屏蔽'console.log(window.someGlobal);' –
不起作用。 'this.someGlobal'或'window.someGlobal'或'eval('someGlobal')' – josh3736
您不能限制使用“呼叫”或“应用”方法功能的范围,但可以使用“EVAL”和范围基本上隐藏功能的任何特定的全局变量是使用一个简单的技巧调用。
这样做的原因是因为函数有权访问在该函数本身什么声明范围内声明的“全局”变量。因此,通过复制该方法的代码并在eval中注入它,可以实质上改变您正在调用的函数的全局范围。最终结果基本上可以在一定程度上对一段JavaScript代码进行沙箱处理。
这里是一个完整的代码示例:
<html>
<head>
<title>This is the page title.</title>
<script>
function displayTitle()
{
alert(document.title);
}
function callMethod(method)
{
var code = "" +
// replace global "window" in the scope of the eval
"var window = {};" +
// replace global "document" in the scope of the eval
"var document = {}; " +
"(" +
// inject the Function you want to call into the eval
method.toString() +
// call the injected method
")();" +
"";
eval(code);
}
callMethod(displayTitle);
</script>
</head>
<body></body>
</html>
是被eval'd看起来像这样的代码:后期
var window = {};
var document = {};
(function displayTitle()
{
alert(document.title);
})();
[不起作用。](http://jsfiddle.net/josh3736/JJPBt/)该函数仍在全局范围内调用,所以全部你必须做'this.document.title'。 – josh3736
@ josh3736易于使用.call({})或.apply({})修复 - http://jsfiddle.net/agoywobt/ –
有一点,但也许它会帮助你有点
function RestrictFunction(params) {
params = (params == undefined ? {} : params);
var scope = (params.scope == undefined ? window : params.scope);
var data = (params.data == undefined ? {} : params.data);
var script = (params.script == undefined ? '' : params.script);
if (typeof params.script == 'function') {
script = params.script.toString();
script = script.substring(script.indexOf("{") + 1, script.lastIndexOf("}"));
}
// example: override native functions that on the white list
var setTimeout = function(_function,_interval) {
// this is important to prevent the user using `this` in the function and access the DOM
var interval = scope.setTimeout(function() {
RestrictFunction({
scope:scope,
data:data,
script:_function
});
} , _interval);
// Auto clear long user intervals
scope.setTimeout(function() {
scope.clearTimeout(interval);
} , 60*1000);
return interval;
}
// example: create custom functions
var trace = function(str) {
scope.console.log(str);
}
return (function() {
// remove functions, objects and variables from scope
var queue = [];
var WhiteList = [
"Blob","Boolean","Date","String","Number","Object","Array","Text","Function",
"unescape","escape","encodeURI","encodeURIComponent","parseFloat","parseInt",
"isNaN","isFinite","undefined","NaN",
"JSON","Math","RegExp",
"clearTimeout","setTimeout"
];
var properties = Object.getOwnPropertyNames(scope);
for (var k = 0; k<properties.length; k++) {
if (WhiteList.indexOf(properties[k])!=-1) continue;
queue.push("var "+properties[k]+" = undefined;");
}
for (var k in scope) {
if (WhiteList.indexOf(k)!=-1) continue;
queue.push("var "+k+" = undefined;");
}
queue.push("var WhiteList = undefined;");
queue.push("var params = undefined;") ;
queue.push("var scope = undefined;") ;
queue.push("var data = undefined;") ;
queue.push("var k = undefined;");
queue.push("var properties = undefined;");
queue.push("var queue = undefined;");
queue.push("var script = undefined;");
queue.push(script);
try {
return eval('(function(){'+ queue.join("\n") +'}).apply(data);');
} catch(err) { }
}).apply(data);
}
使用示例
// dummy to test if we can access the DOM
var dummy = function() {
this.notify = function(msg) {
console.log(msg);
};
}
var result = RestrictFunction({
// Custom data to pass to the user script , Accessible via `this`
data:{
prop1: 'hello world',
prop2: ["hello","world"],
prop3: new dummy()
},
// User custom script as string or function
script:function() {
trace(this);
this.msg = "hello world";
this.prop3.notify(this.msg);
setTimeout(function() {
trace(this);
} , 10);
trace(data);
trace(params);
trace(scope);
trace(window);
trace(XMLHttpRequest);
trace(eval);
return "done!"; // not required to return value...
},
});
console.log("result:" , result);
这并非万无一失。 “trace((function(){return this()));”仍然可以访问全球范围(还有其他方式)。 –
使用嵌入式Web工人可能允许运行安全功能。像这样的东西允许用户输入JavaScript,运行它并获得结果,而无需访问您的全局上下文。
globalVariable = "I'm global";
document.getElementById('submit').onclick = function() {
createWorker();
}
function createWorker() {
// The text in the textarea is the function you want to run
var fnText = document.getElementById('fnText').value;
// You wrap the function to add a postMessage
// with the function result
var workerTemplate = "\
function userDefined(){" + fnText +
"}\
postMessage(userDefined());\
onmessage = function(e){console.log(e);\
}"
// web workers are normally js files, but using blobs
// you can create them with strings.
var blob = new Blob([workerTemplate], {
type: "text/javascript"
});
var wk = new Worker(window.URL.createObjectURL(blob));
wk.onmessage = function(e) {
// you listen for the return.
console.log('Function result:', e.data);
}
}
<div>Enter a javascript function and click submit</div>
<textarea id="fnText"></textarea>
<button id="submit">
Run the function
</button>
您可以在文本区域粘贴尝试这些例如:
return "I'm a safe function";
你可以看到,它的安全:
return globalVariable;
你甚至可以有更复杂的脚本,如下所示:
var a = 4, b = 5;
function insideFn(){
// here c is global, but only in the worker context
c = a + b;
}
insideFn();
return c;
查看关于webworkers的信息在这里,特别是嵌入式网络工作者: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#Embedded_workers
是否可以将参数传递给用户定义的函数? –
@DulguunOtgon您可以通过将函数添加到函数userDefined(parameters)来传递字符串参数{... –
您可以使用WebWorkers隔离代码:
创建一个完全独立和并行执行环境(即一个单独的线程或进程或同等构造),并在该上下文中异步运行其余的这些步骤。
下面是一个简单的例子:
someGlobal = 5;
//As a worker normally take another JavaScript file to execute we convert the function in an URL: http://stackoverflow.com/a/16799132/2576706
function getScriptPath(foo) {
return window.URL.createObjectURL(new Blob([foo], {
type: 'text/javascript'
}));
}
function protectCode(code) {
var worker = new Worker(getScriptPath(code));
}
protectCode('console.log(someGlobal)'); // prints 10
protectCode('console.log(this.someGlobal)');
protectCode('console.log(eval("someGlobal"))');
protectCode('console.log(window.someGlobal)');
该代码将返回:
Uncaught ReferenceError: someGlobal is not defined
undefined
Uncaught ReferenceError: someGlobal is not defined
和
Uncaught ReferenceError: window is not defined
让你的代码现在是安全的。
编辑:这个答案不隐藏window.something变量。但它有一个干净的方式来运行用户定义的代码。我试图找到一种方法来掩盖窗口变量
您可以使用JavaScript函数Function.prototype.bind()提交功能,你所选择的自定义范围变量的用户绑定,在这个自定义的范围,你可以选择共享哪些变量与用户定义的功能,以及隐藏。对于用户定义的函数,代码将能够访问使用this.variableName共享的变量。下面是详细阐述理念的例子:
// A couple of global variable that we will use to test the idea
var sharedGlobal = "I am shared";
var notSharedGlobal = "But I will not be shared";
function submit() {
// Another two function scoped variables that we will also use to test
var sharedFuncScope = "I am in function scope and shared";
var notSharedFuncScope = "I am in function scope but I am not shared";
// The custom scope object, in here you can choose which variables to share with the custom function
var funcScope = {
sharedGlobal: sharedGlobal,
sharedFuncScope: sharedFuncScope
};
// Read the custom function body
var customFnText = document.getElementById("customfn").value;
// create a new function object using the Function constructor, and bind it to our custom-made scope object
var func = new Function(customFnText).bind(funcScope);
// execute the function, and print the output to the page.
document.getElementById("output").innerHTML = JSON.stringify(func());
}
// sample test function body, this will test which of the shared variables does the custom function has access to.
/*
return {
sharedGlobal : this.sharedGlobal || null,
sharedFuncScope : this.sharedFuncScope || null,
notSharedGlobal : this.notSharedGlobal || null,
notSharedFuncScope : this.notSharedFuncScope || null
};
*/
<script type="text/javascript" src="app.js"></script>
<h1>Add your custom body here</h1>
<textarea id="customfn"></textarea>
<br>
<button onclick="submit()">Submit</button>
<br>
<div id="output"></div>
该示例执行以下操作:
据我所知,在Javascript中,任何在函数外声明的变量都属于全局作用域,因此可以从代码中的任何位置访问。
每个函数都有自己的作用域,并且该函数中声明的任何变量只能从该函数和任何嵌套函数中访问。 JavaScript中的本地范围仅由函数创建,也称为函数范围。
把功能的其他功能里面可能是一个可能性,在那里你可以达到降低范围(即嵌套的范围)
看看http://www.adsafe.org/ –
有一件事你肯定可以做的是避免使用全局变量,无论如何这是一个很好的做法 – Pointy
@Pointy:这仍然不能防止不可信的代码访问DOM并修改你的页面。 – josh3736