【问题标题】:Javascript eval (and friends)Javascript eval(和朋友)
【发布时间】:2012-03-05 04:54:07
【问题描述】:

有人声称 eval 是邪恶的。

任何常规的 HTML 页面可能如下所示:

        <script src="some-trendy-js-library.js"></script>
    </body>
</html>

也就是说,假设执行此操作的人知道他的工作并让 javascript 在页面末尾加载。

在这里,我们基本上是将脚本文件加载到网络浏览器中。有些人更深入,并以此作为与 3rd 方服务器通信的一种方式......

<script src="//foo.com/bar.js"></script>

此时,无论出于何种原因,在运行时有条件地实际加载这些脚本非常重要。

我的观点是什么?虽然机制不同,但我们正在做同样的事情......将一段纯文本作为代码执行 - 又名 eval()


既然我已经明确了我的观点,那么问题来了……

给定某些条件,例如 AJAX 请求,或者(更有趣的是)websocket 连接,执行服务器响应的最佳方式是什么?

这里有几个让你思考......

  • eval() 服务器的输出。 (那边那个人是不是晕倒了?)
  • 运行服务器返回的命名函数:var resp = sock.msg; myObj[resp]();
  • 构建我自己的解析器,以找出服务器试图告诉我的内容,而无需直接弄乱 javascript。

【问题讨论】:

  • 您的第三个选项实际上并不是执行来自服务器的响应的选项,只是处理它。如果您要包含该选项,那么将 JSON 和 XML 作为选项也包含在内似乎是合理的。
  • @T.J.Crowder - 但是 JSON 和 XML 只是传输格式。我见过人们将函数(代码)作为字符串返回(最大兼容性),而其他人则在 JSON 中嵌入函数(仅适用于 eval-ing JSON,而不适用于浏览器自己的方法)。第三种选择只是在解释语言中解释语言的过度设计努力。 ://
  • 我希望您不从服务器执行代码,而是编写从服务器读取结果并基于此执行操作的代码。否则,您将面临严重的安全问题。
  • @GoldenNewby - 是什么让你认为我从服务器返回的代码是安全的?
  • 在请求您无法控制的内容时,您提出问题的目的是否在于指出脚本请求并不比 eval() 更安全?

标签: javascript eval server-response


【解决方案1】:

给定某些条件,例如 AJAX 请求,或者(更有趣的)websocket 连接,从服务器执行响应的最佳方式是什么?

在用于解析消息结果时,对eval 的主要批评是它过度杀伤力——你正在使用大锤来拍打苍蝇,而过度使用的工具会带来额外的风险——它们可能会反弹并击中你。

让我们将响应类型分为几个不同的类别:

  1. 按需加载静态 javascript
  2. 来自受信任来源在安全通道上的动态响应,其中不包含不受信任方指定的内容。
  3. 来自混合来源(可能大部分受信任,但包括不受信任方指定的编码字符串)的动态响应,主要是数据
  4. 基于数据的副作用

对于(1),XHR+eval&lt;script src&gt;没有区别,但是XHR+eval优势不大。

对于 (2),差别不大。如果您可以使用JSON.parse 解压缩响应,您可能会遇到更少的问题,但eval 的额外权限不太可能被来自受信任来源的数据滥用,所以如果您已经eval 有充分的理由。

对于(3),有很大的不同。即使您非常小心,eval 的过度滥用权限也可能会咬到您。这在安全方面是脆弱的。不要这样做。

对于(4),最好能把它分成数据问题和代码问题。如果您可以在执行前验证结果,JSONP 允许这样做。使用JSON.parse 或其他几乎没有滥用权限的东西来解析数据,因此您编写并批准用于外部使用的函数会产生副作用。这最大限度地减少了过度滥用的权力。天真的eval在这里很危险。

【讨论】:

  • 但是,使用 JSONP,您无法阻止源站点将恶意 JavaScript 代码直接放入返回的脚本内容中。换句话说,JSONP 是完全可滥用的。 (嗯,传统的 JSONP 到第三方域。)
  • @Pointy,当通过&lt;script src=...&gt; 加载 JSONP 时,你绝对是对的。但是,如果您将 JSONP 视为消息格式IdentifierName '(' DataBundle ')',那么您可以通过过滤代理对其进行路由,将其加载到单独域中的 iframe 中并使用跨帧消息传递来获取数据,或者执行许多其他操作以减轻响应带来的副作用风险。我得到的基本思想是,将数据与副作用分开并允许您使用不同的策略来验证每种策略的消息格式更安全。
  • 由于我更喜欢​​使用 JSON,我一直在考虑让服务器返回一个“数据包类型”,它指示应该对响应执行什么操作;执行或只是静态使用。
  • @MikeSamuel 是的,这是真的——这就是我所说的“传统”资格。我从来没有听说过这样消费 JSONP;这会很棘手,因为您基本上必须使用专门的 JSON 解析器来解析整个响应,以解释函数调用中的外部 ()。如果您出于某种原因确实需要这样做,我想这不会那么糟糕。
  • @MikeSamuel {"t":0,"p":{"x":5,"y":7}} vs {"t":1,"p":"if(a)b();"} (t=type, p=payload)
【解决方案2】:

"Evil" does not mean "forbidden"。有时,使用所谓的“邪恶”功能是有充分理由的。它们只是被称为“邪恶”,因为它们可能被滥用,而且经常被滥用。

在您的情况下,客户端脚本只允许向“它自己的”服务器发出请求。这是原始 JavaScript 来自同一台服务器,因此动态响应与原始代码一样受信任。 eval() 的一个完全有效的场景。

【讨论】:

  • 我被告知,一般来说,eval() 比将脚本获取到当前范围要慢得多(总共)。我必须说所有这些eval 危言耸听让我远离这个,因为获取的代码最终应该在我当前的范围内。
  • @ChristianSciberras:eval 确实在玩有范围的时髦游戏。具体来说,代码是在您调用eval 的范围内评估的,而不是在全局范围内。所以function foo(msg) { eval('alert(msg);'); } foo("Hi"); 提醒“嗨”,function foo(msg) { eval('msg = "bye";'); alert(msg); } foo("Hi"); 提醒“再见”。这是eval 邪恶的原因之一。如果您要从服务器执行 code,请使用 script 元素,这样至少您是在通常的位置执行此操作。但如果该服务器不在您的控制之下,请了解需要大量信任。
  • @T.J.Crowder 是否有可能有一个“缓冲区”脚本,我可以在其中投入 javascript 执行?
  • @T.J.Crowder -- 为什么这种行为“时髦”或“邪恶”? eval 在与函数调用相同的范围内运行代码是完全合理的。
  • @ChristianSciberras, eval 曾经是解析 JSON 的最快方式,现在仍然在 IE 6 上使用。在较新的浏览器上,即使是非原生 JSON 解析器也可以更快,这仅仅是因为 eval必须拥有所有机器来解析更大更复杂的语言。
【解决方案3】:

如果您从不受您控制的域中获取代码,那么将“原始”代码交给 JavaScript 解释器总是意味着您必须完全信任该域,否则您不必关心是否是恶意的代码会破坏您自己的页面。

如果你控制了这个领域,那么就为所欲为。

【讨论】:

  • 不,绝对不会那样做。我们假设我们的连接是通过 SSL 进行的,并且没有窃听者。
  • 您拥有该域吗?它在你的控制之下吗?如果不是,那么它是否是 SSL 都没关系。您信任其他一些主机,而您的网页(可能还有您的网站)的完整性依赖于不被违反的信任。
  • 这是我的同一个域,具有用于最初加载页面的相同安全控制(即,希望是 SSL)。
  • @ChristianSciberras 那么在这种情况下你担心什么?您可能已经将 JavaScript 文件直接包含到您的页面中。它们在页面加载后显示有什么区别?
  • 我只想正确地做这件事,总比使用eval() 好。有人曾经说过“评估永远不是解决方案”。
【解决方案4】:

服务器应该为您提供数据,而不是代码。您应该让服务器响应您的 JS 代码可以相应执行的 JSON 数据。让服务器发送要使用 myObj[resp](); 调用的函数的名称仍然是服务器逻辑与客户端逻辑紧密耦合。

如果没有一些示例代码,很难提供更多建议。

【讨论】:

  • 服务器逻辑在这里并不重要。不管你喜不喜欢,服务器都会返回代码、表示和结构。那时,重要的是如何返回这些东西。
  • 我不同意,我的 AJAX 和 WebSocket 调用 从不 返回代码。它们返回 JS 代码使用的数据对象。将代码放入您的 Web 服务中可以紧密耦合您的代码。一个例子是,您的 Web 服务将不能被 iOS 应用程序使用,而如果您设计 AJAX/WebSockets 以确保只检索数据,您应该能够重用您的服务器端代码用于网络应用、iOS 应用、Android 应用……
  • 顺便说一句,我不认为 eval 总是邪恶的。我的问题是客户端和服务器之间的紧密耦合代码。
  • 好点。我试图保持尽可能轻耦合。服务器将返回的是导致方法执行的条件,而不是特定于平台的任何内容。
【解决方案5】:

让您的服务器返回 JSON,并在客户端解释该 JSON。客户端会弄清楚如何处理 JSON,就像服务器会弄清楚如何处理客户端收到的请求一样。

如果您的服务器开始返回可执行代码,那么您就有问题了。不是因为“坏”的事情会发生(尽管它可能),而是因为您的服务器不负责知道客户端是什么或不应该做什么

这就像向服务器发送代码并期望服务器执行它。除非您有非常好的理由(例如浏览器内的 IDE),否则这是个坏主意。

尽可能多地使用eval,只要确保你分工。

编辑:

我看到了这个逻辑的缺陷。服务器显然是在告诉客户端该做什么,仅仅是因为它提供了客户端执行的脚本。但是,我的观点是服务器端代码不应该在运行中生成脚本。服务器应该是编排的,而不是生产的。

【讨论】:

  • +1 有趣的是,浏览器内的 IDE 正是我正在做的。 :)
  • 哇哦:+1!当“大男孩”回应时,我往往不会得到+。
  • 关于编辑,我应该坚持这一点。
  • 我不喜欢我的服务器为我做饭。那是厨师的工作。
  • 我认为克里斯托弗和我在说同样的话。
猜你喜欢
  • 2015-02-24
  • 2011-08-10
  • 1970-01-01
  • 2015-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-15
  • 1970-01-01
相关资源
最近更新 更多