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

IT技术 javascript coding-style eval
2021-02-06 19:19:52

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

然而,eval()如果我能避免它,我总是回避使用它,因为它是邪恶的(不管对错,我一直认为它在 JavaScript 中更加邪恶,因为要评估的代码可能会被用户更改)。

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

6个回答

我想花一点时间来解决您的问题的前提 - eval() 是“邪恶的”。编程语言人员使用的邪恶这个词通常意味着“危险”,或者更准确地说“能够用一个看起来简单的命令造成很多伤害”。那么,什么时候可以使用危险的东西呢?当您知道危险是什么,并采取适当的预防措施时。

说到点子上,让我们来看看使用 eval() 的危险。和其他一切一样,可能存在许多小的隐患,但两大风险——eval() 被认为是邪恶的原因——是性能和代码注入。

  • 性能 - eval() 运行解释器/编译器。如果您的代码被编译,那么这是一个大打击,因为您需要在运行时调用一个可能很重的编译器。但是,JavaScript 仍然主要是一种解释型语言,这意味着在一般情况下调用 eval() 不会对性能造成很大的影响(但请参阅下面我的具体评论)。
  • 代码注入 - eval() 可能会在提升的权限下运行一串代码。例如,以管理员/root 身份运行的程序永远不会想要 eval() 用户输入,因为该输入可能是“rm -rf /etc/important-file”或更糟。同样,浏览器中的 JavaScript 没有这个问题,因为无论如何该程序都在用户自己的帐户中运行。服务器端 JavaScript 可能存在这个问题。

关于你的具体情况。据我了解,您是自己生成字符串,因此假设您小心地不允许生成像“rm -rf something-important”这样的字符串,则不存在代码注入风险(但请记住,它非常非常在一般情况下很难确保这一点)。此外,如果您在浏览器中运行,那么代码注入的风险很小,我相信。

至于性能,您必须权衡编码的难易程度。我的观点是,如果您正在解析公式,您最好在解析期间计算结果,而不是运行另一个解析器(eval() 中的那个)。但是使用 eval() 编码可能更容易,并且性能下降可能不会引起注意。在这种情况下,看起来 eval() 并不比任何其他可能为您节省一些时间的函数更邪恶。

重新“代码注入 - ... 再说一次,浏览器中的 JavaScript 没有那个问题,”&“此外,如果您在浏览器中运行,那么代码注入的风险很小,我相信。” 你是说浏览器中的代码注入不是问题吗?XSS 多年来一直在 OWASP 的前 10 名漏洞中名列前 3 名。
2021-03-17 19:19:52
如果您完全关心用户的数据,代码注入对于 javascript 来说是一个非常严重的问题。注入的代码将运行(在浏览器中),就好像它来自您的站点一样,让它执行用户可以手动执行的任何类型的恶作剧。如果您允许(第三方)代码进入您的页面,它可以代表您的客户订购东西,或者更改他们的头像,或者他们可以通过您的网站执行的任何操作。要非常小心。让黑客拥有您的客户与让他们拥有您的服务器一样糟糕。
2021-03-18 19:19:52
您没有解决使用 eval 难以调试的代码问题
2021-03-22 19:19:52
@Sean McMillan:我想相信你,但如果有人要拦截和更改eval()从你的服务器发送的 javascript ,他们也可以首先更改页面的源代码,并控制用户的信息。. . 我看不出有什么区别。
2021-03-29 19:19:52
如果数据来自您的服务器并且它是由您(开发人员)生成的,则使用 eval() 没有任何害处。真正的伤害是相信你读到的一切。你看到很多人说 eval() 是邪恶的,他们不知道为什么,只是他们在某处读过它。
2021-03-30 19:19:52

eval()不邪恶。或者,如果是的话,它就像反射、文件/网络 I/O、线程和 IPC 在其他语言中是“邪恶的”一样邪恶。

如果,为了您的目的eval()比手动解释更快,或者使您的代码更简单或更清晰……那么您应该使用它。如果两者都不是,那么你不应该。就那么简单。

更快、更简单、更清晰……这个答案并没有很好地涵盖安全隐患。
2021-03-09 19:19:52
这是非常通用的建议,它可以应用于任何存在的代码块。它真的没有给这个问题添加任何东西;特别是,它无助于来这里的任何人确定他们的特定用法是否有问题。
2021-03-26 19:19:52
我问了一个问题,说明了 eval 的使用,这导致这里的代码更简单、更清晰
2021-03-31 19:19:52
一个这样的目的可能是生成优化的代码,这些代码要么太长,要么太重复而无法手动编写。在 LISP 中需要宏的那种东西。
2021-04-04 19:19:52

当您信任来源时。

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

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

eval也不会正确解析所有有效的 JSON 字符串。例如JSON.parse(' "\u2028" ') === "\u2028"eval(' "\u2028" ')会引发异常,因为 U+2028 是 JavaScript 中的换行符,但就 JSON 而言,它不是换行符。
2021-03-11 19:19:52
@Tomalak 说得很漂亮,我现在在回答中提到了这一点!惊人的!
2021-03-13 19:19:52
@Justin - 如果协议遭到破坏,那么,通常初始页面加载会通过相同的协议发送,然后这是一个有争议的问题,因为客户端已经尽可能地受到损害。
2021-03-22 19:19:52
在 eval() 中使用 json 字符串之前,应始终针对 json 语法对其进行测试。因此 json 字符串“{foo:alert('XSS')}”不会通过,因为“alert('XSS')”不是一个正确的值。
2021-03-30 19:19:52
那么,使用HTTPS。OTOH:中间人不是花园式网络应用程序的典型攻击场景,而即跨站点脚本是。
2021-04-03 19:19:52

让我们来看看真正的人:

  1. 现在每个主要浏览器都有一个内置控制台,您的潜在黑客可以大量使用它来调用具有任何值的任何函数 - 他们为什么要费心使用 eval 语句 - 即使他们可以?

  2. 如果编译 2000 行 JavaScript 需要 0.2 秒,那么如果我对四行 JSON 求值,我的性能下降是什么?

甚至 Crockford 对“eval 是邪恶的”的解释也很薄弱。

eval is Evil,eval 函数是 JavaScript 中最容易被误用的特性。躲开它

正如克罗克福德本人可能会说的那样“这种说法往往会产生非理性的神经症。不要买它。”

理解 eval 并知道它何时可能有用更重要。例如, eval 是用于评估由您的软件生成的服务器响应的明智工具。

顺便说一句:Prototype.js 直接调用 eval 5 次(包括在 evalJSON() 和 evalResponse() 中)。jQuery 在 parseJSON 中使用它(通过 Function 构造函数)。

@AkashKava 您没有意识到的是,如果我在评论框中提交 javascript,并且该 javascript 会将其放入数据库。当另一个用户查看该评论(我将 javascript 放入其中)时,eval 将在呈现该 javascript 时获取该 javascript,并使用解释器对其进行评估,从而导致我嵌入的 javascript 在其他用户的浏览器上执行。通过这样做,我可以收集各种信息。他们的用户名、他们在数据库中的用户 ID、他们的电子邮件地址等。这不是一个很难回答的问题,如果你用谷歌搜索过 XSS,你会在大约 10 秒内看到为什么会出现问题。
2021-03-12 19:19:52
重新“现在每个主要浏览器都有一个内置的控制台......”。当一个用户可以输入然后在另一个用户的浏览器中运行的代码时,代码注入就是一个问题。浏览器控制台本身不允许一个用户在另一个用户的浏览器中运行代码,因此在决定是否值得防止代码注入时,它们无关紧要。
2021-03-22 19:19:52
@akkishore,如果您提出一个真实的例子来支持您的陈述,我将不胜感激。
2021-03-22 19:19:52
“现在每个主流浏览器都有一个内置的控制台……他们为什么要费心使用 eval 语句?” - 你离题了。我建议你编辑答案。一个用户能够注入可以在另一个浏览器中运行的代码是一个主要问题。这就是你需要变得真实的地方。
2021-03-24 19:19:52
JQuery 使用浏览器的内置 JSON.parse 函数(如果可用)(更快和更安全),仅使用 eval 作为回退机制。声明“eval is evil”是一个相当好的指导方针。
2021-04-05 19:19:52

我倾向于遵循克罗克福德的意见eval(),并完全避免。即使看起来需要它的方法也不需要。例如,setTimeout()允许您传递函数而不是 eval。

setTimeout(function() {
  alert('hi');
}, 1000);

即使它是可信来源,我也不使用它,因为 JSON 返回的代码可能是乱码,这充其量可能会做一些不稳定的事情,最坏的情况是暴露一些不好的东西。

你根本不应该依赖你的 javascript 代码......你不依赖任何在客户端运行的东西......如果有人进行中间人攻击,他为什么要弄乱你的 json 对象?他可以为您提供不同的网页和不同的 js 文件...
2021-03-18 19:19:52
我个人不喜欢“总有其他方法可以做到这一点”的论点。例如,您也可以说总有办法避免面向对象编程。这并不意味着它不是一个很好的选择。如果您了解 eval 及其危险,那么它可以成为在正确情况下使用的绝佳工具。
2021-03-19 19:19:52
我认为服务器端 JSON 格式化程序中的错误肯定是一个问题。来自服务器的响应是否取决于任何类型的用户提交的文本?然后你必须注意 XSS。
2021-03-22 19:19:52
如果有人可以执行中间人攻击,他就可以轻松地向您的脚本注入任何内容。
2021-03-25 19:19:52
如果您的网络服务器未通过 HTTPS 进行身份验证,那么您可能会遭受某种中间人攻击,其中另一台主机拦截请求并发送自己的数据。
2021-04-08 19:19:52