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

发布于 2024-07-07 08:08:49 字数 259 浏览 5 评论 0原文

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

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

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

I'm writing some JavaScript code to parse user-entered functions (for spreadsheet-like functionality). Having parsed the formula I could convert it into JavaScript and run eval() on it to yield the result.

However, I've always shied away from using eval() if I can avoid it because it's evil (and, rightly or wrongly, I've always thought it is even more evil in JavaScript, because the code to be evaluated might be changed by the user).

So, when it is OK to use it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(27

爱要勇敢去追 2024-07-14 08:08:49

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

言归正传,我们来看看使用eval()的危险性。 就像其他事情一样,可能存在许多小隐患,但两大风险 - eval() 被认为是邪恶的原因 - 是性能和代码注入。

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

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

至于性能,您必须权衡编码的便捷性。 我认为,如果您正在解析公式,您最好在解析期间计算结果,而不是运行另一个解析器(eval() 内的解析器)。 但使用 eval() 编码可能更容易,并且性能影响可能不会明显。 在这种情况下,看起来 eval() 并不比任何其他可能节省您时间的函数更邪恶。

I'd like to take a moment to address the premise of your question - that eval() is "evil". The word "evil", as used by programming language people, usually means "dangerous", or more precisely "able to cause lots of harm with a simple-looking command". So, when is it OK to use something dangerous? When you know what the danger is, and when you're taking the appropriate precautions.

To the point, let's look at the dangers in the use of eval(). There are probably many small hidden dangers just like everything else, but the two big risks - the reason why eval() is considered evil - are performance and code injection.

  • Performance - eval() runs the interpreter/compiler. If your code is compiled, then this is a big hit, because you need to call a possibly-heavy compiler in the middle of run-time. However, JavaScript is still mostly an interpreted language, which means that calling eval() is not a big performance hit in the general case (but see my specific remarks below).
  • Code injection - eval() potentially runs a string of code under elevated privileges. For example, a program running as administrator/root would never want to eval() user input, because that input could potentially be "rm -rf /etc/important-file" or worse. Again, JavaScript in a browser doesn't have that problem, because the program is running in the user's own account anyway. Server-side JavaScript could have that problem.

On to your specific case. From what I understand, you're generating the strings yourself, so assuming you're careful not to allow a string like "rm -rf something-important" to be generated, there's no code injection risk (but please remember, it's very very hard to ensure this in the general case). Also, if you're running in the browser then code injection is a pretty minor risk, I believe.

As for performance, you'll have to weight that against ease of coding. It is my opinion that if you're parsing the formula, you might as well compute the result during the parse rather than run another parser (the one inside eval()). But it may be easier to code using eval(), and the performance hit will probably be unnoticeable. It looks like eval() in this case is no more evil than any other function that could possibly save you some time.

帅冕 2024-07-14 08:08:49

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

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

eval() isn't evil. Or, if it is, it's evil in the same way that reflection, file/network I/O, threading, and IPC are "evil" in other languages.

If, for your purpose, eval() is faster than manual interpretation, or makes your code simpler, or more clear... then you should use it. If neither, then you shouldn't. Simple as that.

请恋爱 2024-07-14 08:08:49

当你信任来源时。

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

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

When you trust the source.

In case of JSON, it is more or less hard to tamper with the source, because it comes from a web server you control. As long as the JSON itself contains no data a user has uploaded, there is no major drawback to use eval.

In all other cases I would go great lengths to ensure user supplied data conforms to my rules before feeding it to eval().

一杆小烟枪 2024-07-14 08:08:49

让我们来真正的人:

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

  2. 如果编译 2000 行 JavaScript 需要 0.2 秒,那么如果我评估四行 JSON

甚至克罗克福德对“评估是邪恶的”的解释也是站不住脚的。

eval 是邪恶的,eval 函数是最常被滥用的功能
JavaScript。 避免它

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

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

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

Let's get real folks:

  1. Every major browser now has a built-in console which your would-be hacker can use with abundance to invoke any function with any value - why would they bother to use an eval statement - even if they could?

  2. If it takes 0.2 seconds to compile 2000 lines of JavaScript, what is my performance degradation if I eval four lines of JSON?

Even Crockford's explanation for 'eval is evil' is weak.

eval is Evil, The eval function is the most misused feature of
JavaScript. Avoid it

As Crockford himself might say "This kind of statement tends to generate irrational neurosis. Don't buy it."

Understanding eval and knowing when it might be useful is way more important. For example, eval is a sensible tool for evaluating server responses that were generated by your software.

BTW: Prototype.js calls eval directly five times (including in evalJSON() and evalResponse()). jQuery uses it in parseJSON (via Function constructor).

椵侞 2024-07-14 08:08:49

对于 eval(),我倾向于遵循 Crockford 的建议,并避免使用它共。 即使看起来需要它的方式也不需要它。 例如,setTimeout() 允许您传递函数而不是 eval。

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

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

I tend to follow Crockford's advice for eval(), and avoid it altogether. Even ways that appear to require it do not. For example, the setTimeout() allows you to pass a function rather than eval.

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

Even if it's a trusted source, I don't use it, because the code returned by JSON might be garbled, which could at best do something wonky, at worst, expose something bad.

执妄 2024-07-14 08:08:49

Eval 是对用于模板化代码的编译的补充。 我所说的模板化是指您编写一个简化的模板生成器,它可以生成有用的模板代码,从而提高开发速度。

我编写了一个框架,开发人员不使用 EVAL,但他们使用我们的框架,而该框架又必须使用 EVAL 来生成模板。

使用以下方法可以提高 EVAL 的性能; 您必须返回一个函数,而不是执行脚本。

var a = eval("3 + 5");

应该组织成

var f = eval("(function(a,b) { return a + b; })");

var a = f(3,5);

Caching f肯定会提高速度。

Chrome 还允许非常轻松地调试此类功能。

关于安全性,使用或不使用eval几乎没有什么区别,

  1. 首先,浏览器在沙箱中调用整个脚本。
  2. 任何在 EVAL 中是邪恶的代码,在浏览器本身中也是邪恶的。 攻击者或任何人都可以轻松地在 DOM 中注入脚本节点并执行任何操作(如果他/她可以评估任何内容)。 不使用 EVAL 不会产生任何影响。
  3. 有害的主要是服务器端安全性差。 服务器上不良的 cookie 验证或不良的 ACL 实施会导致大多数攻击。
  4. 最近,Java 的本机代码中存在 Java 漏洞等。 JavaScript 过去和现在都被设计为在沙箱中运行,而小程序被设计为在带有证书等的沙箱外运行,这会导致漏洞和许多其他问题。
  5. 编写模仿浏览器的代码并不困难。 您所要做的就是使用您最喜欢的用户代理字符串向服务器发出 HTTP 请求。 无论如何,所有测试工具都会模拟浏览器; 如果攻击者想要伤害您,EVAL 是他们的最后手段。 他们有许多其他方法来处理服务器端安全。
  6. 浏览器 DOM 无法访问文件,也无法访问用户名。 事实上,机器上没有任何东西可供 eval 访问。

如果您的服务器端安全性足够可靠,任何人都可以从任何地方进行攻击,那么您不必担心 EVAL。 正如我提到的,如果 EVAL 不存在,攻击者就有很多工具可以侵入您的服务器,无论您的浏览器的 EVAL 功能如何。

Eval 仅适用于生成一些模板,以根据未使用的内容进行复杂的字符串处理提前。 例如,我更喜欢

"FirstName + ' ' + LastName"

As 而不是

"LastName + ' ' + FirstName"

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

Eval is complementary to compilation which is used in templating the code. By templating I mean that you write a simplified template generator that generates useful template code which increases development speed.

I have written a framework, where developers don't use EVAL, but they use our framework and in turn that framework has to use EVAL to generate templates.

Performance of EVAL can be increased by using the following method; instead of executing the script, you must return a function.

var a = eval("3 + 5");

It should be organized as

var f = eval("(function(a,b) { return a + b; })");

var a = f(3,5);

Caching f will certainly improve the speed.

Also Chrome allows debugging of such functions very easily.

Regarding security, using eval or not will hardly make any difference,

  1. First of all, the browser invokes the entire script in a sandbox.
  2. 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.
  3. It is mostly poor server-side security that is harmful. Poor cookies validation or poor ACL implementation on the server causes most attacks.
  4. 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.
  5. 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.
  6. 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.

If your server-side security is solid enough for anyone to attack from anywhere, you should not worry about EVAL. As I mentioned, if EVAL would not exist, attackers have many tools to hack into your server irrespective of your browser's EVAL capability.

Eval is only good for generating some templates to do complex string processing based on something that is not used in advance. For example, I will prefer

"FirstName + ' ' + LastName"

As opposed to

"LastName + ' ' + FirstName"

As my display name, which can come from a database and which is not hardcoded.

ぺ禁宫浮华殁 2024-07-14 08:08:49

底线

如果您创建或清理了您评估的代码,那么它绝不会邪恶

稍微更详细一点,

如果在服务器上运行时使用客户端提交的输入运行,则eval邪恶,而该客户端不是由开发人员创建的或者是 >未经开发商清理

如果在客户端上运行,eval不是邪恶的即使使用客户端制作的未经净化的输入

显然,您应该始终清理输入,以便对代码消耗的内容进行一定的控制。

推理

客户端可以运行他们想要的任何任意代码,即使开发人员没有编码; 这不仅适用于评估的内容,也适用于对 eval 本身的调用。

Bottom Line

If you created or sanitized the code you eval, it is never evil.

Slightly More Detailed

eval is evil if running on the server using input submitted by a client that was not created by the developer or that was not sanitized by the developer.

eval is not evil if running on the client, even if using unsanitized input crafted by the client.

Obviously you should always sanitize the input, as to have some control over what your code consumes.

Reasoning

The client can run any arbitrary code they want to, even if the developer did not code it; This is true not only for what is evaled, but the call to eval itself.

萌逼全场 2024-07-14 08:08:49

在 Chrome (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() 不一定引用本机 eval() 函数。 这完全取决于函数的名称。 因此,当使用别名调用本机 eval() 时(比如 var noval = eval;),然后在内部函数 noval(expression); 中, >) 那么当表达式引用了应该是闭包一部分但实际上不是闭包一部分的变量时,它的求值可能会失败。

When debugging in Chrome (v28.0.1500.72), I found that variables are not bound to closures if they are not used in a nested function that produces the closure. I guess, that's an optimization of the JavaScript engine.

BUT: when eval() is used inside a function that causes a closure, ALL the variables of outer functions are bound to the closure, even if they are not used at all. If someone has the time to test if memory leaks can be produced by that, please leave me a comment below.

Here's my test code:

(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();
})();

What I like to point out here is, that eval() must not necessarily refer to the native eval() function. It all depends on the name of the function. So when calling the native eval() with an alias name (say var noval = eval; and then in an inner function noval(expression);) then the evaluation of expression may fail when it refers to variables that should be part of the closure, but is actually not.

木槿暧夏七纪年 2024-07-14 08:08:49

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

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

现在这篇文章的尾声是:

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

I saw people advocate to not use eval, because is evil, but I saw the same people use Function and setTimeout dynamically, so they use eval under the hoods :D

BTW, if your sandbox is not sure enough (for example, if you're working on a site that allow code injection) eval is the last of your problems. The basic rule of security is that all input is evil, but in case of JavaScript even JavaScript itself could be evil, because in JavaScript you can overwrite any function and you just can't be sure you're using the real one, so, if a malicious code start before you, you can't trust any JavaScript built-in function :D

Now the epilogue to this post is:

If you REALLY need it (80% of the time eval is NOT needed) and you're sure of what you' re doing, just use eval (or better Function ;) ), closures and OOP cover the 80/90% of the case where eval can be replaced using another kind of logic, the rest is dynamically generated code (for example, if you're writing an interpreter) and as you already said evaluating JSON (here you can use the Crockford safe evaluation ;) )

你好,陌生人 2024-07-14 08:08:49

唯一应该使用 eval() 的情况是当您需要动态运行动态 JS 时。 我说的是从服务器异步下载的 JS...

...10 次中有 9 次你可以通过重构轻松避免这样做。

The only instance when you should be using eval() is when you need to run dynamic JS on the fly. I'm talking about JS that you download asynchronously from the server...

...And 9 times of 10 you could easily avoid doing that by refactoring.

虫児飞 2024-07-14 08:08:49

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

eval is rarely the right choice. While there may be numerous instances where you can accomplish what you need to accomplish by concatenating a script together and running it on the fly, you typically have much more powerful and maintainable techniques at your disposal: associative-array notation (obj["prop"] is the same as obj.prop), closures, object-oriented techniques, functional techniques - use them instead.

长梦不多时 2024-07-14 08:08:49

在服务器端,eval 在处理外部脚本(例如 sql、influxdb 或 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\"}`"
  }
}

然后允许,

  • 通过 json 中的文字字符串直接注入对象/值,对于模板化文本很有用

    通过

  • 可以用作比较器,假设我们制定规则如何验证 CMS 中的任务或事件

缺点:

  • 可能会出现错误如果没有经过充分测试,代码中可能会出现错误,并且会破坏服务中的事物。

    如果没有

  • 如果黑客可以在您的系统上编写脚本,那么您就完蛋了。

  • 验证脚本的一种方法是将脚本的哈希值保存在安全的地方,以便您可以在运行之前检查它们。

    验证脚本的一种方法是将

On the server side eval is useful when dealing with external scripts such as sql or influxdb or mongo. Where custom validation at runtime can be made without re-deploying your services.

For example an achievement service with following metadata

{
  "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\"}`"
  }
}

Which then allow,

  • Direct injection of object/values thru literal string in a json, useful for templating texts

  • Can be use as a comparator, say we make rules how to validate quest or events in CMS

Con of this:

  • Can be errors in the code and break up things in the service, if not fully tested.

  • If a hacker can write script on your system, then you are pretty much screwed.

  • One way to validate your script is keep the hash of your scripts somewhere safe, so you can check them before running.

难理解 2024-07-14 08:08:49

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

Eval isn't evil, just misused.

If you created the code going into it or can trust it, it's alright.
People keep talking about how user input doesn't matter with eval. Well sort of~

If there is user input that goes to the server, then comes back to the client, and that code is being used in eval without being sanitized. Congrats, you've opened pandora's box for user data to be sent to whoever.

Depending on where the eval is, many websites use SPAs, and eval could make it easier for the user to access application internals that otherwise wouldn't have been easy. Now they can make a bogus browser extension that can tape into that eval and steal data again.

Just gotta figure what's the point of you using the eval. Generating code isn't really ideal when you could simply make methods to do that sort of thing, use objects, or the like.

Now a nice example of using eval.
Your server is reading the swagger file that you have created. Many of the URL params are created in the format {myParam}. So you'd like to read the URLs and then convert them to template strings without having to do complex replacements because you have many endpoints. So you may do something like this.
Note this is a very simple example.

const params = { id: 5 };

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

// use eval(route); to do something

瑶笙 2024-07-14 08:08:49

由于还没有人提到它,让我补充一下 eval 对于 Webassemble-Javascript 互操作非常有用。 虽然在页面中包含可供 WASM 代码直接调用的预制脚本当然是理想的选择,但有时这是不切实际的,您需要从 C# 等 WebAssembly 语言传入动态 Javascript 才能真正完成您需要做的事情。

在这种情况下它也是安全的,因为您可以完全控制传入的内容。嗯,我应该说,它并不比使用 C# 编写 SQL 语句安全,也就是说,它需要小心完成(正确转义字符串等) .) 每当使用用户提供的数据来生成脚本时。 但有了这个警告,它在互操作情况下就有了明确的地位,并且远非“邪恶”。

Since no one has mentioned it yet, let me add that eval is super useful for Webassembly-Javascript interop. While it's certainly ideal to have pre-made scripts included in your page that your WASM code can invoke directly, sometimes it's not practicable and you need to pass in dynamic Javascript from a Webassembly language like C# to really accomplish what you need to do.

It's also safe in this scenario because you have complete control over what gets passed in. Well, I should say, it's no less safe than composing SQL statements using C#, which is to say it needs to be done carefully (properly escaping strings, etc.) whenever user-supplied data is used to generate the script. But with that caveat it has a clear place in interop situations and is far from "evil".

゛清羽墨安 2024-07-14 08:08:49

就客户端脚本而言,我认为安全问题是一个有争议的问题。 加载到浏览器中的所有内容都可以进行操作,并且应该如此对待。 当有更简单的方法来执行 JavaScript 代码和/或操作 DOM 中的对象(例如浏览器中的 URL 栏)时,使用 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>

As far as client script goes, I think the issue of security is a moot point. Everything loaded into the browser is subject to manipulation and should be treated as such. There is zero risk in using an eval() statement when there are much easier ways to execute JavaScript code and/or manipulate objects in the DOM, such as the URL bar in your browser.

javascript:alert("hello");

If someone wants to manipulate their DOM, I say swing away. Security to prevent any type of attack should always be the responsibility of the server application, period.

From a pragmatic standpoint, there's no benefit to using an eval() in a situation where things can be done otherwise. However, there are specific cases where an eval SHOULD be used. When so, it can definitely be done without any risk of blowing up the page.

<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>
很快妥协 2024-07-14 08:08:49

代码生成。 我最近编写了一个名为 Hyperbars 的库,它弥补了 virtual-dom车把。 它通过解析车把模板并将其转换为 hyperscript 来实现此目的。 超脚本首先作为字符串生成,在返回它之前,使用 eval() 将其转换为可执行代码。 我发现在这种特殊情况下,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() 的性能也不是问题,因为您只需要解释生成的字符串一次,然后多次重复使用可执行输出。

如果您好奇,您可以看到代码生成是如何实现的 在这里

Code generation. I recently wrote a library called Hyperbars which bridges the gap between virtual-dom and handlebars. It does this by parsing a handlebars template and converting it to hyperscript. The hyperscript is generated as a string first and before returning it, eval() it to turn it into executable code. I have found eval() in this particular situation the exact opposite of evil.

Basically from

<div>
    {{#each names}}
        <span>{{this}}</span>
    {{/each}}
</div>

To this

(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({}))

The performance of eval() isn't an issue in a situation like this too because you only need to interpret the generated string once and then reuse the executable output many times over.

You can see how the code generation was achieved if you're curious here.

等你爱我 2024-07-14 08:08:49

当您没有宏时,Eval 对于代码生成很有用。

举个(愚蠢的)例子,如果你正在编写一个 Brainfuck 编译器,你可能会想要构造一个以字符串形式执行指令序列的函数,并对其进行评估以返回一个函数。

Eval is useful for code generation when you don't have macros.

For (a stupid) example, if you're writing a Brainfuck compiler, you'll probably want to construct a function that performs the sequence of instructions as a string, and eval it to return a function.

痴情 2024-07-14 08:08:49

我认为任何评估合理的案例都是罕见的。 您更有可能认为它是合理的而使用它,而不是在它实际上合理时才使用它。

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

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

I think any cases of eval being justified would be rare. You're more likely to use it thinking that it's justified than you are to use it when it's actually justified.

The security issues are the most well known. But also be aware that JavaScript uses JIT compilation and this works very poorly with eval. Eval is somewhat like a blackbox to the compiler, and JavaScript needs to be able to predict code ahead of time (to some extent) in order to safely and correctly apply performance optimisations and scoping. In some cases, the performance impact can even affect other code outside eval.

If you want to know more:
https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch2.md#eval

温柔少女心 2024-07-14 08:08:49

如果您可以完全控制传递给 eval 函数的代码,则可以使用它。

It's okay to use it if you have complete control over the code that's passed to the eval function.

╭⌒浅淡时光〆 2024-07-14 08:08:49

如果可能的话,仅在测试期间。 另请注意,eval() 比其他专用 JSON 等评估器慢得多。

Only during testing, if possible. Also note that eval() is much slower than other specialized JSON etc. evaluators.

韵柒 2024-07-14 08:08:49

只要您可以确定代码的来源来自您或实际用户,就没有理由不使用 eval()。 尽管他可以操纵发送到 eval() 函数的内容,但这不是安全问题,因为他能够操纵网站的源代码,因此可以更改 JavaScript 代码本身。

那么...什么时候不使用 eval() ? 仅当第三方有可能更改 Eval() 时,才不应使用 Eval()。 就像拦截客户端和服务器之间的连接一样(但如果这是一个问题,请使用 HTTPS)。 您不应该使用 eval() 来解析其他人(例如在论坛中)编写的代码。

There is no reason not to use eval() as long as you can be sure that the source of the code comes from you or the actual user. Even though he can manipulate what gets sent into the eval() function, that's not a security problem, because he is able to manipulate the source code of the web site and could therefore change the JavaScript code itself.

So... when to not use eval()? Eval() should only not be used when there is a chance that a third party could change it. Like intercepting the connection between the client and your server (but if that is a problem use HTTPS). You shouldn't eval() for parsing code that is written by others like in a forum.

长发绾君心 2024-07-14 08:08:49

如果确实需要 eval 并不是邪恶的。 但是我偶然发现的 99.9% 的 eval 用法都是不需要的(不包括 setTimeout 的东西)。

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

If it's really needed eval is not evil. But 99.9% of the uses of eval that I stumble across are not needed (not including setTimeout stuff).

For me the evil is not a performance or even a security issue (well, indirectly it's both). All such unnecessary uses of eval add to a maintenance hell. Refactoring tools are thrown off. Searching for code is hard. Unanticipated effects of those evals are legion.

哽咽笑 2024-07-14 08:08:49

我相信 eval 对于客户端 Web 应用程序来说是一个非常强大的函数,并且安全......与 JavaScript 一样安全,但事实并非如此。 :-) 安全问题本质上是服务器端问题,因为现在,使用 Firebug 这样的工具,您可以攻击任何 JavaScript 应用程序。

My belief is that eval is a very powerful function for client-side web applications and safe... As safe as JavaScript, which are not. :-) The security issues are essentially a server-side problem because, now, with tool like Firebug, you can attack any JavaScript application.

贱贱哒 2024-07-14 08:08:49

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

我总是试图阻止使用 eval。 几乎总是有更干净、更可维护的解决方案可用。 即使 JSON 解析也不需要 Eval 。 Eval 增加了维护地狱。 道格拉斯·克罗克福德(Douglas Crockford)等大师对它不屑一顾,这并非没有道理。

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

当您需要传递表达式时。

例如,我有一个构造通用 google.maps.ImageMapType 对我来说对象,但我需要告诉它秘诀,它应该如何从 zoomcoord 参数构建图块 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);
        },
        ....
    });
}

When is JavaScript's eval() not evil?

I'm always trying to discourage from using eval. Almost always, a more clean and maintainable solution is available. Eval is not needed even for JSON parsing. Eval adds to maintenance hell. Not without reason, it is frowned upon by masters like Douglas Crockford.

But I found one example where it should be used:

When you need to pass the expression.

For example, I have a function that constructs a general google.maps.ImageMapType object for me, but I need to tell it the recipe, how should it construct the tile URL from the zoom and coord parameters:

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);
        },
        ....
    });
}
人生戏 2024-07-14 08:08:49

我使用eval的示例:导入

通常是如何完成的。

var components = require('components');
var Button = components.Button;
var ComboBox = components.ComboBox;
var CheckBox = components.CheckBox;
...
// That quickly gets very boring

但在 eval 和一些辅助函数的帮助下,它看起来更好了:

var components = require('components');
eval(importable('components', 'Button', 'ComboBox', 'CheckBox', ...));

importable 可能看起来像(这个版本不支持导入具体成员)。

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;
}

My example of using eval: import.

How it's usually done.

var components = require('components');
var Button = components.Button;
var ComboBox = components.ComboBox;
var CheckBox = components.CheckBox;
...
// That quickly gets very boring

But with the help of eval and a little helper function it gets a much better look:

var components = require('components');
eval(importable('components', 'Button', 'ComboBox', 'CheckBox', ...));

importable might look like (this version doesn't support importing concrete members).

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;
}
尐偏执 2024-07-14 08:08:49

尽管在许多情况下,您可以通过将脚本连接在一起并即时运行来完成您需要完成的任务,但您通常可以使用更强大且可维护的技术。 eval 很少是正确的选择。:关联数组表示法(obj["prop"] 与 obj.prop 相同)、闭包、面向对象技术、函数技术 - 请改用它们。

While there may be numerous instances where you can accomplish what you need to accomplish by concatenating a script together and running it on the fly, you typically have much more powerful and maintainable techniques at your disposal. eval is rarely the right choice.: associative-array notation (obj["prop"] is the same as obj.prop), closures, object-oriented techniques, functional techniques - use them instead.

橪书 2024-07-14 08:08:49

当您使用解析函数(例如 jQuery.parseJSON)解析 JSON 结构时,它期望 JSON 文件具有完美的结构(每个属性名称都用双引号引起来)。 然而,JavaScript 更灵活。 因此,您可以使用 eval() 来避免它。

When you parse a JSON structure with a parse function (for example, jQuery.parseJSON), it expects a perfect structure of the JSON file (each property name is in double quotes). However, JavaScript is more flexible. Therefore, you can use eval() to avoid it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文