Javascript 在这种情况下eval()是邪恶的吗?
您好:)我想知道在这种情况下,Javascript 在这种情况下eval()是邪恶的吗?,javascript,security,eval,Javascript,Security,Eval,您好:)我想知道在这种情况下,eval是否安全: !function(){ var a = 1; !function(){ var b = 2; try { eval.call({}, 'a'); } catch (e) { console.log(e.message); } try { eval.call({}, 'b'); } catch (e) { console.log(e.message
eval
是否安全:
!function(){
var a = 1;
!function(){
var b = 2;
try { eval.call({}, 'a'); }
catch (e) { console.log(e.message); }
try { eval.call({}, 'b'); }
catch (e) { console.log(e.message); }
}();
}();
两个电话都失败了。这是否意味着eval
无法访问周围的范围?换句话说,使用eval.call({},…')
而不是eval('…')
,可以eval
只访问对象的成员吗
这里的一些测试:.如果
eval
没有“调用上下文”(基本上是this
的局部值),那么执行上下文就是全局上下文
因此,这应该是可行的:
!function(){
var a = 1;
function evalWrapper() {
var b = 2;
try { eval('a'); console.log("yaay!"); }
catch (e) { console.log(e.message); }
};
evalWrapper.call({});
}();
规范中描述的第一个场景是:
如果没有调用上下文,或者没有通过对eval函数的直接调用(15.1.2.1.1)计算eval代码,则,a。如10.4.1.1所述,使用评估代码C初始化执行上下文,如同它是全局执行上下文一样 因此,除了直接调用
eval(something)
,您所做的任何事情都包括,如果您阅读了引用的部分,则通过名称“eval”以外的其他名称引用“eval”函数然后在全局上下文(包括全局词汇上下文)中计算字符串中的代码。因此,代码似乎根本不在周围函数中。附加测试
尝试从IIFE内部访问变量
var a = 1;
!function(){
var b = 2;
try { eval.call(null, 'console.log(a)'); }
catch (e) { console.log(e.message); }
try { eval.call(null, 'console.log(b)'); }
catch (e) { console.log(e.message); }
try { eval.call({ c: 3 }, 'console.log(c)'); }
catch (e) { console.log(e.message); }
}();
铬:
1
b没有定义
c没有定义
跨浏览器测试
尝试从IIFE外部访问变量。考虑到Pointy的答案,除了a
之外的所有变量都应该是可访问的
!function () {
var a = 1;
eval.call(window, [
'b = 2;',
'c = function () { return 3; };',
'd = function d() { return 4; };',
'function e() { return 5; };',
'x = function () { return a; };'
].join(' '));
}();
var l = function (a) { console.log(a); };
try { l('window.a -> ' + window.a); } catch(e) { l(e.message); };
try { l('window.b -> ' + window.b); } catch(e) { l(e.message); };
try { l('window.c() -> ' + window.c()); } catch(e) { l(e.message); };
try { l('window.d() -> ' + window.d()); } catch(e) { l(e.message); };
try { l('window.e() -> ' + window.e()); } catch(e) { l(e.message); };
try { l('window.x() -> ' + window.x()); } catch(e) { l(e.message); };
铬合金31,FF 26,IE 8-10:
window.a->未定义
窗口b->2
window.c()->3
window.d()->4
window.e()->5
a没有定义
IE 7的行为不符合预期:
window.a->未定义
窗口b->2
window.c()->3
对象不支持此属性或方法
预期功能
window.x()->1
IE 7和命名函数
似乎命名函数是调用eval
的作用域的一部分:
2
1.
g为null或未定义
窗口级别的跨浏览器评估
实际上,“跨浏览器”的意思是“Chrome 31,FF 26,IE 7-10”:
用法示例:
evil(
'var a = 1; alert(a); a;',
function (r) { console.log(r); },
function (e) { console.log(e.message); }
);
// prints "1"
evil(
'alert(b);',
function (r) { console.log(r); },
function (e) { console.log(e.message); }
);
// prints "b is not defined"
你认为将整个代码封装到一个函数中会使这个模式安全吗?如果它在一个函数中,并且该函数是通过一些上下文调用的,这样就定义了
this
。例如,如果函数是通过对象属性访问的,或者如果您使用.call()
@wared调用周围的函数,那么这个规范在这一点上是非常奇怪的;这可能是有原因的,但我不知道是什么原因。我模糊地记得一篇关于这个主题或相关主题的老Kangax博客文章。eval
只有在您已经知道字符串在解释为JavaScript代码时会做什么时才是“安全的”(就像在您的示例中,字符串是常量)。如果您确实知道,那么有一些简单的解决方案(function(){…}
,context对象)通常运行速度快十几倍,并且没有eval
著名的任何风险。
function evil(code, success, failure) {
var head, script;
script = document.createElement('script');
script.text = [
'try{_logevil[0](eval(\'',
code.replace(/('|\\)/g, '\\\$1'),
'\'))}catch(e){_logevil[1](e);}'
].join('');
window._logevil = [success, failure];
head = document.getElementsByTagName('head')[0];
head.appendChild(script);
head.removeChild(script);
}
evil(
'var a = 1; alert(a); a;',
function (r) { console.log(r); },
function (e) { console.log(e.message); }
);
// prints "1"
evil(
'alert(b);',
function (r) { console.log(r); },
function (e) { console.log(e.message); }
);
// prints "b is not defined"