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

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

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


当前回答

Eval并不邪恶,只是被滥用了。

如果您创建了代码,或者可以信任它,那就没问题。 人们一直在说用户输入对eval不重要。嗯,有点~

如果用户输入到服务器,然后返回到客户端,那么这些代码就被用于eval而没有被净化。恭喜你,你打开了潘多拉的盒子,用户数据可以发送给任何人。

根据eval的位置不同,许多网站都使用spa, eval可以让用户更容易地访问应用程序内部,否则就不容易。现在他们可以做一个虚假的浏览器扩展,可以磁带到评估,并再次窃取数据。

我只是想知道你用评估有什么用。当您可以简单地创建方法来做这类事情,使用对象或类似的事情时,生成代码并不理想。

这是一个很好的使用eval的例子。 您的服务器正在读取您创建的swagger文件。许多URL参数是以{myParam}格式创建的。因此,您希望读取url,然后将它们转换为模板字符串,而不必进行复杂的替换,因为您有许多端点。你可以这样做。 注意,这是一个非常简单的例子。

const params = { id: 5 };

const route = '/api/user/{id}';
route.replace(/{/g, '${params.');

// use eval(route); to do something

其他回答

我倾向于遵循Crockford关于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);

缓存肯定会提高速度。

Chrome也允许调试这样的功能非常容易。

在安全性方面,是否使用eval几乎没有什么区别。

First of all, the browser invokes the entire script in a sandbox. Any code that is evil in EVAL, is evil in the browser itself. The attacker or anyone can easily inject a script node in DOM and do anything if he/she can eval anything. Not using EVAL will not make any difference. It is mostly poor server-side security that is harmful. Poor cookies validation or poor ACL implementation on the server causes most attacks. A recent Java vulnerability, etc. was there in Java's native code. JavaScript was and is designed to run in a sandbox, whereas applets were designed to run outside a sandbox with certificates, etc. that lead to vulnerabilities and many other things. Writing code for imitating a browser is not difficult. All you have to do is make a HTTP request to the server with your favourite user agent string. All testing tools mock browsers anyway; if an attacker want to harm you, EVAL is their last resort. They have many other ways to deal with your server-side security. The browser DOM does not have access to files and not a user name. In fact nothing on the machine that eval can give access to.

如果您的服务器端安全性足够坚固,任何人都可以从任何地方进行攻击,那么您就不应该担心EVAL。正如我提到的,如果EVAL不存在,攻击者就有很多工具来入侵你的服务器,而不管你浏览器的EVAL能力如何。

Eval只适用于生成一些模板,根据事先没有使用的内容进行复杂的字符串处理。例如,我更喜欢

"FirstName + ' ' + LastName"

而不是

"LastName + ' ' + FirstName"

作为我的显示名,它可以来自数据库,并且不是硬编码的。

我认为评价被证明是正确的情况将是罕见的。”你更有可能认为它是合理的,而不是在实际合理的情况下使用它。

安全问题最为人所知。但也要注意JavaScript使用JIT编译,这与eval的工作效果很差。Eval有点像编译器的黑匣子,JavaScript需要能够提前(在某种程度上)预测代码,以便安全正确地应用性能优化和范围。在某些情况下,性能影响甚至会影响eval之外的其他代码。

如果你想了解更多: https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch2.md#eval

什么时候JavaScript的eval()不是邪恶的?

我总是不鼓励使用eval。几乎总是有更干净和可维护的解决方案可用。Eval甚至对于JSON解析也不需要。Eval增加了维护的难度。道格拉斯·克罗克福德(Douglas Crockford)这样的大师并不赞同这一点,这不无道理。

但我发现了一个应该使用它的例子:

当你需要传递表达式时。

例如,我有一个函数,为我构造了一个通用的google.maps.ImageMapType对象,但我需要告诉它配方,它应该如何从缩放和坐标参数构造tile URL:

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也不是坏事。但是我偶然发现的99.9%的eval使用是不需要的(不包括setTimeout的东西)。

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