javascript Eval功能的“不当使用”是什么构成的?[关闭]


13

评估是一个有争议的语言功能。道格拉斯·克罗克福德(Douglas Crockford)坚决反对。我想知道Eval会带来什么具体风险。根据这个问题,Improper use of eval opens up your code for injection attacks

使用Eval命令有哪些不当使用,它们会打开哪些安全漏洞?

Answers:


31

在我实施JScript引擎时,我曾提倡打印EVAL IS EVIL衬衫,但遗憾的是我们从来没有解决过。

我对eval的最大问题不是明显的恶意代码注入攻击,尽管这无疑引起了极大关注。我最大的问题是人们倾向于将其用作“真正的大锤”来解决很小的问题。当我在JScript团队中时,我在野外看到的大多数“ eval”用法实际上可以通过使用查找表来轻松解决。而且由于JScript中的每个对象已经是一个查找表,所以这并不是一个沉重的负担。Eval 再次启动编译器,完全破坏了编译器优化代码的能力

有关此方面的更多想法,请参阅我在2003年发表的有关该主题的文章:

一般罪恶:

http://blogs.msdn.com/b/ericlippert/archive/2003/11/01/53329.aspx

注入攻击罪恶:

http://blogs.msdn.com/b/ericlippert/archive/2003/11/04/53335.aspx


您对eval像JSPacker这样的应用程序喜欢的方式编写大量代码有何想法?JSPacker + gzip通常会产生比单独使用任何一种解决方案都要小的文件大小,但是正如您正确地指出的那样,它实际上是在同一段代码上两次启动编译器,外加一些用于替换字符串的开销。
马修·沙利

2
@Matthew:时空之间通常会进行权衡,利用这种权衡有时可能会是一个巨大的胜利。如果该技术的目的是提高性能,那么我的看法是,如果仔细的测量表明在不引入安全漏洞的情况下,这是在现实情况下的重大胜利,那就这样做。但是我对这种特定技术知之甚少,无法批评其细节。
埃里克·利珀特

我想我已经看到了一个答案无论是在这里在SO本身就已经说明你的第二个链接状态:这eval()不是在客户端(浏览器)代码安全风险。
sq33G 2011年

4

大多数安全漏洞与SQL注入具有相同的漏洞,即将用户输入连接到JavaScript代码中。区别在于,尽管有多种方法可以确保SQL不会发生这种情况,但JavaScript却无能为力。

作为一个简单而无用的示例,一个简单的JavaScript计算器:

textbox1.value = eval(textbox2.value);

一个正确的用法示例是一些JavaScript打包程序,它们通过提取常用单词并将其替换为短的1-2个字符来压缩JavaScript。然后,打包程序会根据生成的字典将所有这些信息与字符串替换代码一起输出,然后评估结果。


1

有一些事情,没有一个eval样的功能是不可能的JS做的(evalFunction,也许更多)。

apply为例。在普通函数调用上使用它很容易:

foo.apply(null, [a, b, c])

但是,如何对通过新语法创建的对象执行此操作?

new Foo.apply(null, [a, b, c]) 不起作用,类似形式也不行。

但是您可以通过evalFunctionFunction在本示例中使用)来解决此限制:

Function.prototype.New = (function () {
    var fs = [];
    return function () {
        var f = fs[arguments.length];
        if (f) {
            return f.apply(this, arguments);
        }
        var argStrs = [];
        for (var i = 0; i < arguments.length; ++i) {
            argStrs.push("a[" + i + "]");
        }
        f = new Function("var a=arguments;return new this(" + argStrs.join() + ");");
        if (arguments.length < 100) {
            fs[arguments.length] = f;
        }
        return f.apply(this, arguments);
    };
}) ();

例:

Foo.New.apply(null, [a, b, c]);

当然,您可以手动构建使用的函数Function.prototype.New,但不仅冗长又笨拙,而且(根据定义)必须是有限的。Function允许代码适用于任意数量的参数。


2
的确如此,但是OP的问题是“ 对Eval命令有哪些不当使用,它们会打开哪些安全漏洞? ”,而不是“ 对Eval有什么好用eval()
Ross Patterson

1
@RossPatterson:猜猜我主要看了问题的标题哈哈。
Thomas Eding

不过,+ 1可以很好地利用不良的语言功能:-)
Ross Patterson

1

就我而言,一个直接的答案是开发面向开发人员的API测试区域。我们在页面上提供了一个文本区域,以及一个“运行”按钮。该页面的中心是使他们能够针对我们的iframe-communication API在Javascript中进行尝试,而这些操作在本地环境中并非易事。

在那种情况下可能发生的任何恶意行为,也都可以通过开发人员打开其F12工具来完成。


0

我确实同意应该很少使用它,但是我已经找到了一个强大的用例eval

我一直在使用Firefox中的一项实验性新功能,称为asm.js。它允许将Java语言的有限子集编译为本机代码。是的,这非常棒,但是确实有局限性。您可以将Javascript的有限子集视为嵌入在Javascript中的类C语言。它并不是真的要被人类阅读或书写。

Javascript的这一有限子集不允许我在编译后将运行时生成的代码注入到已编译的代码中。

我编写了一些代码,允许用户以熟悉的符号编写数学表达式,并将其即时转换为asm.js代码。除非我不想在服务器端处理代码(我不希望这样做),否则它eval是唯一允许我实时将结果代码由浏览器处理的工具。


0

正如其他人指出的那样,与之合作时最重要的eval是确保其安全。为此,您需要进行彻底的参数检查,并使eval代码简单,因为维护和保护运行时生成的代码通常要困难得多。

话虽这么说,我喜欢用eval两种东西(即使可能有更好,更少邪恶的选择):

  1. 由于这eval是“显式缓存代码”的一种方式,因此可以用来提高性能。请注意,优化器始终在不断改进,但是无法保证它们可以为您做些什么。通过使代码中的内容明确,实际上可以帮助优化器做出更明智的决策。
  2. 它也可以用于提供基本类型的安全性以及JS缺少的其他语言功能,而不会降低性能。

例如,这种预编译的对象迭代器方法eval用于对象属性迭代时显示出明显的性能优势。它还显示了功能强大的类型系统的开端,该系统可以提供隐式约束检查以及更多的功能,而几乎没有成本。

许多经验丰富的Javascript开发人员可能会指出这是一个难题,因为如果您开始以这种方式编写Java脚本,则实际上会改变使用该语言的方式。但是,对于那些喜欢使用Javascript但又缺少基本语言功能的人来说,这不一定是一件坏事,这些功能只能通过更改我们使用语言本身的方式来实现。


-3

我遇到一种情况,其中eval看起来很像,评估一个字符串并返回一个名称与字符串相同的现有变量。

我有几个表:table1ResultsTable,table2ResultsTable,tableNResultsTable。我用相同的名称设置了变量,它们是jQuery数据表对象。我用它们来设置表并在它们上调用jQuery datatable函数。

每个表都分配了class =“ resultsTable”。现在,我需要在单击表时获取变量。我正在这样做:

$('resultsTable).on('click', 'td', function(event) {
    var cResultsTable = eval(event.target.parentElement.parentElement.parentElement.id);
    [etc]
});

因此,我得到了在其中单击该单元格的表的ID,该ID与与其对应的datatable对象变量同名。如果有人有改进的建议,我想知道。


1
为什么需要评估?id应该是一个纯字符串,而不是代码。无论如何,event.target.parentElement.parentElement.parentElement太可怕了。此外,我希望eval调用会产生“参考错误:[id]未定义”错误,除非您故意使用可评估的id(它是残破的,错误的,如果结束则可能会导致奇怪的事情发生)生成重复的ID)。
布莱恩

也许我没有说清楚。id是一个纯字符串。这是已单击的表的ID。我还有一个对象变量(使用jQuery datatable()方法设置,引用相同的表),其名称与id相同。我正在尝试获取该变量,以在单击表时访问其功能(实际上是将“ row_selected”类添加到所选行)。自从我写了这篇文章以来,我已经提出了一个改进。我只是将所有对象引用放入数组中,将元素命名为与id相同的名称,然后将id字符串插入其中以获取对象ref。
BobRodes

布赖恩,如果您有更好的方法来查找已单击的表的ID,我将不知所措。对于datatables函数,我需要处理单元格的click事件,并将row_selected类添加到其parentNode中。为什么我不能只处理row事件并将类直接添加到其中,我不知道,但是当我这样做时,该行并没有显示为选中状态。
BobRodes

1
也许我没有说清楚。如果您在普通(即非JS)字符串上调用eval,则会引发异常。因此,您对eval的使用没有任何意义。如果您正巧生成与id相同名称的对象变量,则您的代码可以工作...但是让我感到震惊。我宁愿使用来创建变量document.getElementById(ID).MySpecialProperty = MYSPECIALPROPERTYVALUE(也不是说它很棒,但它比eval更好)。正如埃里克·利珀特(Eric Lippert)指出的那样,“ JScript中的每个对象已经是一个查询表”。
布莱恩

好的,您是说要向元素引用添加属性并将其设置为数据表对象引用?对我来说,这听起来也更紧。
BobRodes
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.