当JavaScript的eval()不邪恶吗?
-
10-07-2019 - |
题
我写一些JavaScript code分析用户输入的职能(对于电子表格等功能性).具有分析式我 可能 转换成JavaScript和运行 eval()
它产生的结果。
然而,我总是回避使用 eval()
如果我可以避免它因为它是邪恶的(而且,正确地或错误地,我一直认为它甚至更为邪恶的JavaScript,因为代码来进行评价可能是通过改变用户)。
因此,当它是确定使用它?
解决方案
我想花一点时间来解决的前提下你的问题-这eval()是"邪恶的".单词"邪恶的",因为使用编程语言的人,通常意味着在"危险",或更确切地说"能够造成大量的伤害与一个看起来简单的命令"。因此,当它是确定为使用危险的东西?当你知道有什么危险的是,当你采取适当的预防措施。
到这点,让我们看看危险,在使用eval().有可能是许多小的隐藏的危险就像其他的一切,但两个巨大的风险-因为什么eval()被认为是邪恶的-都是性能和代码注射。
- 绩效eval()运行的翻译/编译器。如果你的代码汇编,然后这是一个很大的打击,因为你需要叫有可能重编译器中运行时间。然而,JavaScript仍然主要是一个解释的语言,这意味着叫eval()不是一个很大的性能打在一般情况下(但是看到我的具体评论下文)。
- 代码注eval()潜在的运行一串的代码,在提升的权限。例如,一个运行的程序作为管理员/根不会想eval()用户输入的,因为这种投入可能是"rm-rf/etc/重要文件的",或者更糟。再次,JavaScript在浏览器中没有这方面的问题,因为程序正在运行的用户自己的账户。服务器的端JavaScript可能有这样的问题。
在您的具体情况。从我的理解,你在产生串自己,所以假设你小心,不要允许一串像"rm-rf的东西重要的"产生,有没有代码注射风险(但请记住,它的 非常非常难 确保这个在一般情况)。还有,如果你是在浏览器中运行的代码然后注射是一个很小的风险,我相信。
作为性能,就必须重,对易的编码。我认为,如果你分析式,您可能会以及计算结果在分析而不是运行的另一个分析器(一个内部eval()).但它可以更容易代码使用eval(),和绩效打击可能会不明显。它看起来像eval()在这种情况下是没有更多的邪恶比任何其他功能,可能可以节省一些时间。
其他提示
eval()
不是恶。或者,如果它是,它以同样的方式邪恶的反射,文件/网络I / O,线程和IPC在其他语言中是“邪恶”。
如果,你的目的的,<=>比人工快的解释,或者让你的代码更简单,更清晰...那么你应该使用它。如果没有,那么你不应该。简单。
在信任源。
在JSON的情况下,更多或更少的硬与源篡改,因为它来自自己控制的Web服务器。只要JSON本身不包含任何数据的用户上载,存在使用eval没有主要的缺点。
在所有其他情况下,我会去竭尽全力确保喂养它给eval()之前用户提供的数据符合我的规则。
我们得到真正的人:
每一个主要的浏览器现在有一个内置的控制台上,你想成为的黑客可以利用丰富援引任何的功能与任何价值-他们为什么要刻意去使用一个eval声明-即使他们可以?
如果需要0.2秒汇编2000年行JavaScript,我的性能退化,如果我eval四条线象?
甚至Crockford的解释,对'eval是邪恶的'是微弱的。
eval是邪恶的,eval功能是最被滥用的特征 JavaScript。避免它
作为Crockford自己可能会说"这种声明往往会产生不合理的神经官能症。不要买它。"
了解eval,并知道当它可能是有用的方式更重要。例如,eval是一个明智的工具,用于评估服务器的反应,产生,通过你的软件。
顺便说一句:Prototype.js 呼叫eval直接的五倍(包括在evalJSON()和evalResponse()).jQuery使用它在parseJSON(通过功能constructor).
我倾向于遵循克罗克福德的意见获取eval()
,并完全避免。即使是似乎需要它没有办法。例如,setTimeout()
允许传递函数,而不是EVAL。
setTimeout(function() {
alert('hi');
}, 1000);
即使这是一个的信任的来源,我不使用它,因为JSON返回的代码可能会出现乱码,这最多只能做一些靠不住的,在最坏的情况,揭露坏事。
Eval是互补的汇编,其中使用的模板的代码。由模板我的意思是,你写的简化模板发生器,产生有用的模板的代码这增加了发展的速度。
我已经写了一个框架,开发人员不使用EVAL,但他们使用我们的框架,并在把这一框架已经使用EVAL生成模板。
性能EVAL可以增加通过使用以下方法;而不是执行该脚本,你必须回报的功能。
var a = eval("3 + 5");
它应当组织为
var f = eval("(function(a,b) { return a + b; })");
var a = f(3,5);
缓存f肯定会提高速度。
还有铬允许调试这样的功能非常容易。
关于安全,使用eval或不会不作任何区别,
- 首先,浏览器中援引的整个剧本,在沙箱。
- 任何代码这就是邪恶的,在EVAL,是邪恶的浏览器本身。攻击者或任何人都可以很容易注入一个脚本节点在DOM和做任何事情,如果他/她可以eval任何东西。不EVAL不会做出任何差异。
- 它主要是贫穷的服务器侧的安全是有害的。可怜的饼干验证或可怜的ACL的执行服务器上导致大多数攻击。
- 最近Java脆弱性,等等。在那里,在Java的母代码。JavaScript是被设计和运行在沙箱,而应用程序设计为在外面跑,sandbox证书,等等。这导致脆弱性和许多其他的事情。
- 编写代码,用于模仿浏览器是不困难的。你所要做的就是做一个HTTP请求到服务器你最喜欢的用户代理串。所有的测试工具模拟浏览器;如果攻击者想要伤害你,EVAL是他们最后的手段。他们有许多其他的方式来处理你的服务器侧的安全。
- 浏览器DOM没有访问的文件并不是一个用户名。事实上没有机eval可以给访问。
如果你的服务器侧的安全是不够扎实,任何人都可以攻击任何地方,你不应该担心EVAL。正如我所提到的,如果EVAL就不会存在,攻击者有许多工具来侵入服务器无关的浏览器的EVAL能力。
Eval仅仅是良好的用于产生一些模板做串复杂的处理的基础上的东西是不是用在提前。例如,我会更喜欢
"FirstName + ' ' + LastName"
作为反对
"LastName + ' ' + FirstName"
我的名称显示,它可能来自一个数据库,并不是硬编码.
我看到人们主张不使用eval,因为是的恶的,但我看到了同样的人使用功能和setTimeout的动态,所以他们使用eval的抽油烟机的下: d
顺便说一句,如果你的沙箱是不够的确定(例如,如果你在一个网站,允许代码注入工作)EVAL是最后你的问题。安全的基本规则是:所有的输入是邪恶的,但在JavaScript中的甚至的JavaScript的情况下本身可能是邪恶的,因为在JavaScript中可以覆盖任何功能,你只要能“T为确保您使用的真实的,所以,如果你之前一个恶意代码开始,你不能相信任何JavaScript内置函数:d
现在的尾声此篇是:
如果您真的需要它(时间的EVAL 80%是不会需要),你确定你正在做什么,只是使用eval(或更好功能;)),关闭和OOP覆盖壳体的80/90%,其中的eval可以使用其它类型的逻辑来代替,其余是动态生成的代码(例如,如果你正在写一个解释器),当你已经说了评估JSON(在这里你可以使用克罗克福德安全评价;))
当在浏览器(v28.0.1500.72)进行调试时,我发现如果它们不是在产生封闭的嵌套函数中使用的变量未绑定到闭包。我想,这就是JavaScript引擎的优化。
<强> BUT 强>:当eval()
是一种使封闭,的在函数内部中使用的所有强>的外功能的变量绑定到闭合,即使它们不在所有使用。如果有人来测试内存泄漏可以通过产生的时间,请给我留下了评论如下。
这是我的测试代码:
(function () {
var eval = function (arg) {
};
function evalTest() {
var used = "used";
var unused = "not used";
(function () {
used.toString(); // Variable "unused" is visible in debugger
eval("1");
})();
}
evalTest();
})();
(function () {
var eval = function (arg) {
};
function evalTest() {
var used = "used";
var unused = "not used";
(function () {
used.toString(); // Variable "unused" is NOT visible in debugger
var noval = eval;
noval("1");
})();
}
evalTest();
})();
(function () {
var noval = function (arg) {
};
function evalTest() {
var used = "used";
var unused = "not used";
(function () {
used.toString(); // Variable "unused" is NOT visible in debugger
noval("1");
})();
}
evalTest();
})();
我想在这里指出的是,eval()函数必须不一定是指原生var noval = eval;
功能。的这完全取决于功能强>的名称。因此,与别名时调用本地noval(expression);
(比如expression
,然后在内部函数<=>),那么当它指的是变量,应该是封闭的部分<=>的评估可能会失败,但实际上不是
微软解释为何的eval()是他们在IE浏览器博客缓慢的的 IE + JavaScript的性能的建议2部分:JavaScript代码低效 的
当你应该使用eval的唯一实例()是当你需要在飞行运行动态JS。我说的是,你从服务器异步下载JS ...
...和10 9倍,你可以很容易地避免这样做,通过重构。
这没关系,如果你有过则传递给eval
函数的代码完全控制使用它。
eval
很少是正确的选择。虽然可能有很多情况下,您可以完成你需要串联在一起的脚本,并在飞行运行它来完成的,你通常在您的处置更加强大和维护的技术:关联阵列符号(obj["prop"]
是相同obj.prop
),关闭,面向对象的技术,功能性技术 - 用它们来代替
至于客户端脚本去,我认为安全问题是一个有争议的问题。加载到浏览器一切都受到操纵,应受到同样的对待。有一个在使用时有更容易的方式在DOM执行JavaScript代码和/或操作对象,如在浏览器地址栏一个eval()语句零风险。
javascript:alert("hello");
如果有人想操纵他们的DOM,我说挥杆了。安全,防止任何形式的攻击应该永远是服务器应用程序的责任,期限。
从务实的角度来看,有在那里的东西可以以其它方式进行的情况下使用一个eval()没有好处。不过,也有应当使用一个eval具体案例。如果是这样,它绝对可以不吹了页面的风险做了。
<html>
<body>
<textarea id="output"></textarea><br/>
<input type="text" id="input" />
<button id="button" onclick="execute()">eval</button>
<script type="text/javascript">
var execute = function(){
var inputEl = document.getElementById('input');
var toEval = inputEl.value;
var outputEl = document.getElementById('output');
var output = "";
try {
output = eval(toEval);
}
catch(err){
for(var key in err){
output += key + ": " + err[key] + "\r\n";
}
}
outputEl.value = output;
}
</script>
<body>
</html>
当是JavaScript的的eval()不为恶吗
我总是试图从使用eval 劝阻。一般说来,一个更清洁,维护的解决方案是可用的。 EVAL 甚至没有为JSON解析需要。 EVAL 增加维护地狱一>。不是没有道理的,它是由象道格拉斯Crockford的主人令人难以接受的。
但是我找到一个例子,其中它的应的使用:
:当你需要通过表达强>
例如,我有构造一个一般 google.maps.ImageMapType
对象为我,但我需要告诉它的配方,它应该如何从zoom
构造的图块网址和coord
参数:
my_func({
name: "OSM",
tileURLexpr: '"http://tile.openstreetmap.org/"+b+"/"+a.x+"/"+a.y+".png"',
...
});
function my_func(opts)
{
return new google.maps.ImageMapType({
getTileUrl: function (coord, zoom) {
var b = zoom;
var a = coord;
return eval(opts.tileURLexpr);
},
....
});
}
我使用的eval
例如:进口
如何它通常做。
var components = require('components');
var Button = components.Button;
var ComboBox = components.ComboBox;
var CheckBox = components.CheckBox;
...
// That quickly gets very boring
但随着importable
的帮助和它得到一个更好的看一个小帮手功能:
var components = require('components');
eval(importable('components', 'Button', 'ComboBox', 'CheckBox', ...));
<=>可能看起来像(在此版本不支持导入混凝土构件)。
function importable(path) {
var name;
var pkg = eval(path);
var result = '\n';
for (name in pkg) {
result += 'if (name !== undefined) throw "import error: name already exists";\n'.replace(/name/g, name);
}
for (name in pkg) {
result += 'var name = path.name;\n'.replace(/name/g, name).replace('path', path);
}
return result;
}
在服务器上侧eval是有用的,在处理与外部剧本如sql或这个策略就或mongo.在那里定义的验证在运行时,可没有重新部署的服务。
例如一个实现服务与下列元数据
{
"568ff113-abcd-f123-84c5-871fe2007cf0": {
"msg_enum": "quest/registration",
"timely": "all_times",
"scope": [
"quest/daily-active"
],
"query": "`SELECT COUNT(point) AS valid from \"${userId}/dump/quest/daily-active\" LIMIT 1`",
"validator": "valid > 0",
"reward_external": "ewallet",
"reward_external_payload": "`{\"token\": \"${token}\", \"userId\": \"${userId}\", \"amountIn\": 1, \"conversionType\": \"quest/registration:silver\", \"exchangeProvider\":\"provider/achievement\",\"exchangeType\":\"payment/quest/registration\"}`"
},
"efdfb506-1234-abcd-9d4a-7d624c564332": {
"msg_enum": "quest/daily-active",
"timely": "daily",
"scope": [
"quest/daily-active"
],
"query": "`SELECT COUNT(point) AS valid from \"${userId}/dump/quest/daily-active\" WHERE time >= '${today}' ${ENV.DAILY_OFFSET} LIMIT 1`",
"validator": "valid > 0",
"reward_external": "ewallet",
"reward_external_payload": "`{\"token\": \"${token}\", \"userId\": \"${userId}\", \"amountIn\": 1, \"conversionType\": \"quest/daily-active:silver\", \"exchangeProvider\":\"provider/achievement\",\"exchangeType\":\"payment/quest/daily-active\"}`"
}
}
然后允许,
直接注射对象的价值观,通过文字串式,用于模板的案文
可以用作一比较,说我们的规则如何验证任务或活动CMS
Con:
可代码中的错误,并打破东西在服务,如果没有充分进行测试。
如果一个黑客可以写剧本在你的系统,那么你是漂亮多了。
一种方法来验证你的脚本是保持哈希脚本安全的地方,所以你可以检查他们之前在运行。
我觉得称义的EVAL任何情况下将是罕见的。你更可能使用它认为这是有道理的比你要使用它时,它的真正的理由。
在安全性问题是最公知的。而且要知道,JavaScript使用JIT编译和这个作品非常差与EVAL。 EVAL有点像一个黑的编译器,以及JavaScript需要能够以安全和正确应用性能的优化和范围超前预测码的时间(在某种程度上)。在某些情况下,对性能的影响,甚至影响到外面的eval其他代码。
如果你想知道更多: 的https: //github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch2.md#eval
只有在测试过程中,如果可能的话。还要注意的是的eval()比其他专门JSON等评估慢得多。
代码生成。我最近写了一个名为库 Hyperbars 桥接的虚拟-DOM 和车把一>。它通过解析车把模板,并将其转换为做到这一点 hyperscript 。所述hyperscript作为字符串首先产生并返回它之前,它eval()
把它转换成可执行代码。我在这种特殊情况下发现<=>邪恶的正好相反。
基本上从
<div>
{{#each names}}
<span>{{this}}</span>
{{/each}}
</div>
要此
(function (state) {
var Runtime = Hyperbars.Runtime;
var context = state;
return h('div', {}, [Runtime.each(context['names'], context, function (context, parent, options) {
return [h('span', {}, [options['@index'], context])]
})])
}.bind({}))
<=>的性能是不是在这样的情况下设置的问题,因为你只需要通过一次解释生成的字符串,然后再用可执行输出多次。
您可以看到代码生成是如何实现的,如果你好奇的此处。
有,没有理由不使用eval()只要可以确保代码的源来自您或实际用户。即使他可以操纵什么获取发送到eval()函数,这不是一个安全问题,因为他能够操纵该网站的源代码,因此可以改变的JavaScript代码本身。
所以...当不使用eval()?的eval()只不应时,有一个机会,一个第三方可以改变它使用。像拦截在客户端和服务器之间的连接(但如果这是一个问题使用HTTPS)。你不应该的eval()用于解析由他人在论坛上写的代码。
如果它真正需要的eval是不是罪恶。但EVAL的用途为99.9%,我偶然发现是的不强>需要(不包括的setTimeout的东西)。
有关我的邪恶不是性能,甚至是安全问题(当然,间接地是两个)。 EVAL的所有这些不必要的应用添加到维护地狱。重构工具揭去。搜索代码是很难的。那些evals的非预期效应是多方面的。
我的信念是,EVAL是客户端的Web应用程序和安全......至于安全,如JavaScript,这是不是一个非常强大的功能。 :-)安全问题基本上是一个服务器端的问题,因为,现在,随着类似Firebug工具,可以攻击任何JavaScript应用程序。
评估时,你不必是宏代码生成有用的。
有关(一个笨)例如,如果你正在写一个 Brainfuck 编译器,你“可能会想要构造执行的作为字符串的指令序列的功能,并且EVAL它返回的功能。
在解析JSON结构解析函数(例如,jQuery.parseJSON),它期望JSON文件的一个完美的结构(各属性名是在双引号)。然而,JavaScript是更灵活。因此,可以使用eval(),以避免它。