是否可以限制javascript函数的范围?
假设我在全局范围内有一个变量 假设我希望定义一个我可以保证不会访问此变量的函数,有没有一种方法可以包装该函数或调用该函数,从而确保这一点 事实上,我需要任何规定的函数对变量具有定义良好的访问权限,并且该访问权限必须在函数定义之前定义,并且与函数定义分离 动机:是否可以限制javascript函数的范围?,javascript,security,Javascript,Security,假设我在全局范围内有一个变量 假设我希望定义一个我可以保证不会访问此变量的函数,有没有一种方法可以包装该函数或调用该函数,从而确保这一点 事实上,我需要任何规定的函数对变量具有定义良好的访问权限,并且该访问权限必须在函数定义之前定义,并且与函数定义分离 动机: 我正在考虑用户提交函数的可能性。我应该能够相信该功能是某种“安全”的,因此我很乐意在我自己的网站上发布它们。在托管在不同来源的iframe中运行代码。这是保证不受信任的代码被沙盒化并阻止访问全局或页面DOM的唯一方法。您不能使用“调用”或
我正在考虑用户提交函数的可能性。我应该能够相信该功能是某种“安全”的,因此我很乐意在我自己的网站上发布它们。在托管在不同来源的
iframe
中运行代码。这是保证不受信任的代码被沙盒化并阻止访问全局或页面DOM的唯一方法。您不能使用“调用”或“应用”方法限制函数的范围,但可以使用“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>
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)');
有点晚了,但也许对你有点帮助
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);
}
使用嵌入式Web Workers可以运行安全功能。类似的东西允许用户输入javascript,运行它并获得结果,而无需访问全局上下文
globalVariable=“我是全球的”;
document.getElementById('submit')。onclick=function(){
createWorker();
}
函数createWorker(){
//textarea中的文本是要运行的函数
var fnText=document.getElementById('fnText')。值;
//包装函数以添加postMessage
//与函数结果一致
var workerTemplate=”\
函数userDefined(){“+fnText+
"}\
postMessage(userDefined())\
onmessage=function(e){console.log(e)\
}"
//web Worker通常是js文件,但使用Blob
//可以使用字符串创建它们。
var blob=新blob([workerTemplate]{
键入:“text/javascript”
});
var wk=newworker(window.URL.createObjectURL(blob));
wk.onmessage=函数(e){
//你听着,等待回报。
console.log('函数结果:',e.data);
}
}
输入一个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>
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)');
此代码将返回:
未捕获引用错误:未定义someGlobal
未定义
未捕获引用错误:未定义someGlobal
和
未捕获引用错误:未定义窗口
因此,您的代码现在是安全的。创建具有相同名称的局部变量。 如果有如下全局变量:
var window = {};
var document = {};
(function displayTitle()
{
alert(document.title);
})();
var globalvar;
在你的职能中:
function noGlobal(); {
var globalvar;
}
如果函数引用globalvar,则它将引用本地函数。编辑:此答案不会隐藏窗口变量。但它有一种干净的方式来运行用户定义的代码。我试图找到一种方法来屏蔽窗口变量 您可以使用javascript函数将用户提交的函数绑定到您选择的自定义范围变量,在此自定义范围中,您可以选择与用户定义的函数共享哪些变量,以及隐藏哪些变量。对于用户定义的函数,代码将能够访问您使用this.variableName共享的变量。下面是一个详细阐述该想法的示例:
//我们将使用几个全局变量来测试这个想法
var sharedGlobal=“我是共享的”;
var notSharedGlobal=“但我不会被共享”;
函数提交(){
//我们还将使用另外两个函数作用域变量来测试
var sharedFuncScope=“我在功能范围内并已共享”;
var notSharedFuncScope=“我在函数范围内,但我没有被共享”;
//自定义范围对象,在这里您可以选择与自定义函数共享哪些变量
var funcScope={
sharedGlobal:sharedGlobal,
sharedFuncScope:sharedFuncScope
};
//阅读自定义函数体
var customFnText=document.getElementById(“customfn”).value;
//使用函数构造函数创建一个新的函数对象,并将其绑定到定制的范围对象
var func=新函数(customFnText).bind(funcScope);
//执行该函数,并将输出打印到页面。
document.getElementById(“输出”).innerHTML=JSON.stringify(func());
}
//示例测试函数体,这将测试自定义函数可以访问哪些共享变量。
/*
返回{
sharedGlobal:this.sharedGlobal | | null,
sharedFuncScope:this.sharedFuncScope | | null,
notSharedGlobal:this.notSharedGlobal | | null,
notSharedFuncScope:this.notSharedFuncScope | | null
};
*/
在此处添加自定义实体
提交
据我所知,在Javascript中,函数之外声明的任何变量都属于全局范围,因此可以从代码中的任何地方访问
每个函数都有自己的作用域,在该函数中声明的任何变量都只能从该函数和任何嵌套函数中访问。JavaScript中的局部作用域仅由函数创建,也称为函数作用域
将一个函数放在另一个函数中可能是
<h1>
child
</h1>
<script>
abc = 'child';
function foo() {
console.log('child foo: abc = ', abc);
}
console.log('-calling from child-');
parent.foo();
</script>
-calling from child-
parent foo: abc = parent
-calling from parent-
child foo: abc = child
<h1>parent</h1>
<iframe></iframe>
<script>
const iframe = document.querySelector('iframe');
iframe.addEventListener('load', function() {
console.log('-call from parent-');
const fn = iframe.contentWindow.makeFn(`(
function() {
return abc;
}
)`);
console.log('from fn:', fn());
});
iframe.src = 'child.html';
</script>
<h1>
child
</h1>
<script>
abc = 'child';
function makeFn(s) {
return eval(s);
}
</script>
-call from parent-
from fn: child
function loadIFrame(src) {
return new Promise((resolve) => {
const iframe = document.createElement('iframe');
iframe.addEventListener('load', resolve);
iframe.src = src;
iframe.style.display = 'none';
document.body.appendChild(iframe); // iframes don't load if not in the document?!?!
});
}