我正在编写一些JavaScript代码来解析用户输入的函数(用于类似电子表格的功能)。解析完公式后,我可以将其转换为JavaScript并在其上运行eval()以产生结果。

然而,我总是避免使用eval(),因为它是邪恶的(而且,无论正确与否,我一直认为它在JavaScript中更邪恶,因为要计算的代码可能会被用户更改)。

那么,什么时候可以使用它呢?


当前回答

底线

如果你创建或净化了你评估的代码,它永远不会是邪恶的。

略为详细

如果在服务器上使用不是由开发人员创建或未经过开发人员处理的客户端提交的输入运行Eval是邪恶的。

如果在客户端上运行Eval,即使使用客户端制作的未经处理的输入,它也不是邪恶的。

显然,您应该始终清理输入,以便对代码使用的内容有一定的控制。

推理

客户端可以运行任何他们想要的代码,即使开发人员没有编写这些代码;这不仅适用于被求值的对象,而且适用于对eval本身的调用。

其他回答

当你相信消息来源时。

在JSON的情况下,它或多或少很难篡改源代码,因为它来自你控制的web服务器。只要JSON本身不包含用户上传的数据,使用eval就没有什么大的缺点。

在所有其他情况下,在将用户提供的数据提供给eval()之前,我将竭尽全力确保它符合我的规则。

由于还没有人提到它,让我补充一下eval对于Webassembly-Javascript互操作非常有用。虽然在您的页面中包含WASM代码可以直接调用的预先制作的脚本当然是理想的,但有时这是不可行的,您需要从Webassembly语言(如c#)传入动态Javascript来真正完成您需要做的事情。

在这种情况下,它也是安全的,因为您可以完全控制传入的内容。好吧,我应该说,这并不比使用c#编写SQL语句更安全,也就是说,无论何时使用用户提供的数据来生成脚本,都需要谨慎地执行(正确转义字符串等)。但在这种情况下,它在互操作场景中有一个明确的位置,远非“邪恶”。

我看到有人提倡不要使用eval,因为这是邪恶的,但我也看到同样的人动态地使用Function和setTimeout,所以他们在幕后使用eval:D

顺便说一句,如果你的沙盒不够确定(例如,如果你在一个允许代码注入的网站上工作),eval是你的最后一个问题。安全的基本规则是所有输入都是邪恶的,但对于JavaScript,甚至JavaScript本身也可能是邪恶的,因为在JavaScript中,你可以覆盖任何函数,你只是不能确定你使用的是真正的函数,所以,如果恶意代码在你之前启动,你不能相信任何JavaScript内置函数:D

现在这篇文章的尾声是:

如果你真的需要它(80%的时间不需要eval),并且你确定你在做什么,只使用eval(或更好的Function;)),闭包和OOP覆盖了80/90%的情况,其中eval可以使用另一种逻辑替换,其余是动态生成的代码(例如,如果你正在编写解释器),正如你已经说过的评估JSON(这里你可以使用Crockford安全评估;))

如果真的需要,eval也不是坏事。但是我偶然发现的99.9%的eval使用是不需要的(不包括setTimeout的东西)。

对我来说,邪恶不是性能问题,甚至不是安全问题(好吧,间接地,两者都是)。所有这些不必要的eval使用都增加了维护的难度。重构工具被抛弃了。搜索代码是困难的。这些评估的意想不到的影响是很多的。

Eval很少是正确的选择。虽然在许多情况下,您可以通过将脚本连接在一起并动态运行来完成需要完成的任务,但您通常可以使用更强大和可维护的技术:关联数组符号(obj["prop"]与obj.prop相同)、闭包、面向对象技术、函数技术—请使用它们。