我正在编写一些JavaScript代码来解析用户输入的函数(用于类似电子表格的功能)。 解析了公式后,我可以将其转换为JavaScript并在其上运行eval() 以产生结果。
但是,我总是回避使用eval() 如果我可以避免它,因为它是邪恶的(并且正确或错误地,我一直认为它在JavaScript中更加邪恶,因为要评估的代码可能会被更改 由用户)。
那么,什么时候可以使用它?
实际上,大多数JSON库都没有使用eval来确保防范安全风险。
@Sean - JQuery和Prototype都使用eval(JQuery通过新函数使用它)
@plodder - 你在哪里得到你的信息?自1.4以来,jQuery已经使用了原生的JSON.parse()(早在2010年1月)!亲眼看看:code.jquery.com/jquery-1.4.js
@ ken,Sean它使用JSON.parse如果可用,则IE <= 7不是这种情况
@tobyodavies - 好点,除了说IE <= 7有误导性,因为任何超过几年的浏览器都不会有本机JSON对象。我试图提出的观点是,JS库不喜欢eval() ....它只是旧版浏览器的后备。
@ken,也是好点,不过IE6&amp; IE7仍然在广泛使用,我称之为旧,不确定遗产 - 不幸的是,它们远未死亡。他们肯定不喜欢它,但他们确实在某些情况下使用它,因此他们认为在某些限制下它足够安全。
关于此主题的另一个以javascript为中心的讨论是在stackoverflow.com/questions/4812288/…
"显然,必须使用eval()来解析JSON" - 这不是真的,相反 - 不应该使用eval来解析JSON!使用来自json.org的Douglas Crockfords'(JSON的创建者)json2.js脚本!
@Tomas具有讽刺意味的是,json2.js使用eval来解析JSON
@tobyodavies,哇,这很有趣,记住道格拉斯批评这一点。至少有重型安全检查。
@Tomas,+ 1。实际上,您不能使用eval 来正确解析所有JSON字符串。 JSON.parse('"\u2028" ') 有效但eval('"\u2028" ') 失败并出现异常,因为U + 2028是一个JavaScript换行符,但在未转义的JSON中是允许的。
使用eval 可以显示您的库实现代码,因为它从闭包运行。性能影响也很大,因为它每次都会解析和编译。使用Function 构造函数可以避免这种情况。 Function 构造函数在Global闭包中运行,与调用它的位置无关。如果您计划多次调用此函数,它可能会变得"热"并且JavaScript引擎会对其进行优化。并且由于它返回一个函数对象,您可以将其存储在缓存中以限制对Function 构造函数的调用。
@tobyodavies是的,但是Crockford说除非你需要IE 8支持,否则不要使用json2.js。
@jkdev当这个问题被问到IE8是主流浏览器时,IE9还不到一年。而克罗克福德仅在2周前(在我上次评论后近3年)添加了disclamer
哇,就在2周前?我不知道。
我确实看到了Crockford关于评估嵌入在JSON中的恶意代码的风险的观点。正如@TMS所说,json2.js中有安全检查可以防止这种情况发生。
@jkdev - 更根本的是,你错过了Crockford说不使用该文件,因为JSON已经成为JavaScript的内置功能。 AFAIK,现在,你正在使用[等效功能];但是您要将实施细节留给语言供应商。
@ToolmakerSteve json2.js:你是对的,从用户的角度来看,JSON.parse()的实现方式并不重要。 IE8没有内置的JSON对象,因此您可以使用Crockford的json2.js作为代码中eval 'JSON的更安全的替代方法。这就是它的全部内容。
"解析用户输入的函数(对于类似电子表格的功能)""告诉我,这里的大部分评估都是没有根据的。假设函数没有持久化到DB,javascript函数对单用户单页面级别有什么危害?黑客攻击他/她自己的数据?如果持久化并且不共享,则再次关注用户的范围。坚持和共享(或由他人查看),是的,你有一个XSS注射载体。
eval 总是邪恶的。 没有例外期。 如果要评估代码,请使用window.Function 。 当然有些情况下你可以用eval来做其他事情无法做到的事情,但那些是非法的用例,绝不应该由任何自尊的编码人员执行。
Mozilla非常清楚:不要使用eval!
我想花一点时间来解决你的问题的前提 - eval()是"邪恶的"。编程语言人使用的"邪恶"一词通常意味着"危险",或者更准确地说"能够通过简单的命令造成大量伤害"。那么,什么时候可以使用危险的东西呢?当您知道危险是什么时,以及何时采取适当的预防措施。
至关重点,我们来看看使用eval()的危险性。可能存在许多小的隐患,就像其他一切一样,但两个大的风险 - eval()被认为是邪恶的原因 - 是性能和代码注入。
性能 - eval()运行解释器/编译器。如果你的代码是编译的,那么这是一个很大的问题,因为你需要在运行时调用一个可能很重的编译器。但是,JavaScript仍然主要是一种解释语言,这意味着在一般情况下调用eval()并不是一个很大的性能影响(但请参阅下面的具体说明)。
代码注入 - eval()可能在提升的权限下运行一串代码。例如,以管理员/ root身份运行的程序永远不会想要eval()用户输入,因为该输入可能是"rm -rf / etc / important-file"或更糟。同样,浏览器中的JavaScript没有这个问题,因为程序无论如何都在用户自己的帐户中运行。服务器端JavaScript可能存在这个问题。
根据您的具体情况而定。根据我的理解,你自己生成字符串,所以假设你小心不要生成像"rm -rf something-important"这样的字符串,那么就没有代码注入的风险(但请记住,它非常非常在一般情况下很难确保这一点)。此外,如果你在浏览器中运行,那么代码注入是一个非常小的风险,我相信。
至于性能,你将不得不重视编码的简易性。我认为,如果你正在解析公式,你也可以在解析期间计算结果,而不是运行另一个解析器(eval()中的一个)。但是使用eval()进行编码可能更容易,并且性能损失可能不明显。看起来eval()在这种情况下并不比任何其他可以节省你一些时间的函数更邪恶。
您没有解决使用eval难以调试的代码问题
这里有一个更完整的答案来解决这个问题:stackoverflow.com/questions/951373/when-is-eval-evil-in-php
如果您对用户的数据非常关注,则代码注入是javascript的一个非常严重的问题。注入的代码将(在浏览器中)运行,就像它来自您的网站一样,让它可以执行用户可以手动执行的任何类型的shenanigan。如果您允许(第三方)代码进入您的页面,它可以代表您的客户订购商品,或者更改他们的图片,或者通过您的网站可以做的任何事情。要非常小心。让黑客拥有你的客户与让他们拥有你的服务器一样糟糕。
如果数据来自您的服务器以及您(开发人员)生成的内容,则使用eval()没有任何害处。真正的伤害正在贬低你所阅读的一切。你看到很多人说eval()是邪恶的,他们不知道为什么除了他们在某处读它。
@Sean McMillan:我想相信你,但是如果有人要拦截并从你的服务器改变javascript到eval() ,他们也可以首先改变页面的来源,并控制用户的信息。 。 。我没有看到差异。
@ user27476 - 我同意如果要解析字符串,那么也可以继续进行计算。这就是我要做的,但也许那就是我。
在Chrome上,以下是直接代码,代码级别和函数(代码)()(与eval相同)之间的性能比较:jsperf.com/eval-vs-parse-and-call/2
重新"代码注入 - 再次,浏览器中的JavaScript没有这个问题,"&amp;"另外,如果你在浏览器中运行,那么代码注入是一个非常小的风险,我相信。"您是否建议在浏览器中注入代码不是问题?多年来,XSS一直是OWASP十大榜单中的前三名。
@MikeSamuel,XSS只有在你可以将代码注入其他人的浏览器时才有效("跨站点脚本(XSS)是一种计算机安全漏洞......使攻击者能够将客户端脚本注入其他用户查看的网页中。"维基百科)。因此,如果您评估用户在同一页面上输入的代码,没有任何伤害,没有犯规。如果你允许访客留下未经授权的评论,你就会打开他们留下杜鹃蛋的大门。
@thirdender,是什么让你相信到达eval 的字符串不包含由另一个用户控制的字符?原始问题从未声明电子表格只能由一个用户查看。
@MikeSamuel,每个案例都需要单独处理。这就是我说清理用户输入很重要的原因。但就其本身而言,我认为"eval is evil"并非如此。但是,如果您发现自己认为eval 是唯一的解决方案,那么您应该停下来思考。如果可以避免,最好这样做,但不是不惜一切代价。此外,值得注意的是道格拉斯·克罗克福德("eval is evil"成名)在eval (Javascript:The Good Parts)之后仅谴责无块语句和++ / -- 操作数两页。
@thirdender,我认为你让我感到困惑的是一个说"eval是邪恶的"。
"浏览器中的JavaScript没有这个问题,因为程序无论如何都在用户自己的帐户中运行" - 这并不能完全解决使用eval的问题。如果一个用户输入的脚本是另一个用户的eval(),则会造成严重破坏。答案似乎并不关心这一点。
这与eval的问题不同,就像你设置用户交互的方式一样。用户应该为他们提供已清理过的字符串(如果有任何用户生成的内容被共享)我真的不知道这是eval的错误,确定有使用它的危险,但这与eval无关,如果如果您允许用户生成的内容,那么除了滥用安全性较低的用户之外,您的用户还可以执行许多其他恶意操作
@bobobobo:事实上,eval() 可以帮助调试。请参阅我的帖子stackoverflow.com/questions/197769/…
代码注入:涉及的风险金额取决于eval函数的使用方式。 eval("alert('hello')") 不会带来alert('hello') 的风险,因为在这两种情况下攻击者都需要更改源以更改任何内容。但是,如果像eval这样的东西("users [""+ username +"']")可能会非常危险,因为攻击者只需要设计一个聪明的用户名,他们就可以代表其他用户运行代码。 tl; dr eval 不是邪恶的。 eval +糟糕的节目是邪恶的。
&安培;代码注入可能是一个严重的问题
"浏览器中的JavaScript没有这个问题,因为程序无论如何都在用户自己的帐户中运行。"除非JavaScript是"在机器上安装这个邪恶的恶意软件",否则用户有权执行此操作。
我有一个内部使用的应用程序,我想使用eval()来创建基于我提供的JSON文件的函数。这些函数只影响UI字段的启用,归零等,因此即使JSON被破坏,它也只会破坏UI。如果他们也改变了.js文件,那么他们已经完全控制了。这将是更少的代码...回想起来,我应该做到这一点。
性能:你可以让eval 创建一个能完成工作的函数 - 代码只编译一次(或使用new Function )
对于那些得到40多个upvotes代码注入的老兄来说....任何在用户触摸之前访问您网站的人都可以在您的网站上运行代码,并且可以在未经您许可的情况下删除影响用户数据的自己的js,并且不需要eval来执行此操作。任何在用户触摸它之后注入js的人都可以在没有评估的情况下将他们的js丢弃在你的页面上。这有点类似于使用内容脚本以及无头浏览器或普通旧开发工具的chrome扩展。你可以做的废话是无止境的。我还在等着看客户端js eval evil的一个例子
@AaronLoften黑客不是神。他们没有您的管理员密码。他们默默地抓住你的网站,寻找一些信息和弱点。他们甚至可以使用社会工程来填补空白。没有任何一点英特尔会产生任何严重影响,但总而言之,它可能会成为真正的安全漏洞。注射(包括eval )是蛋糕上的樱桃;这些使攻击完成。谷歌,Facebook,以及大型网上商店和银行,都必须每天处理这个问题。为什么你不读更多关于这个?因为公司不喜欢泄漏他们的胆量。
eval() 不是邪恶的。或者,如果是这样,那就像反射,文件/网络I / O,线程和IPC在其他语言中是"邪恶的"一样是邪恶的。
如果为了您的目的,eval() 比手动解释更快,或者使您的代码更简单或更清晰......那么您应该使用它。如果不是,那么你不应该。就那么简单。
其中一个目的可能是生成优化的代码,这些代码要么太长也不能重复,无法手动编写。 LISP中的那种东西会调用宏。
这是一般性的建议,它可以应用于字面上存在的任何代码块。它真的没有为这个问题添加任何东西;特别是,来到这里的任何人都无法确定他们的特定用途是否有问题。
更快,更简单,更清晰...这个答案并不能很好地涵盖安全隐患。
当你信任来源时。
在JSON的情况下,它或多或少难以篡改源,因为它来自您控制的Web服务器。只要JSON本身不包含用户上传的数据,使用eval就没有重大缺陷。
在所有其他情况下,我会竭尽全力确保用户提供的数据符合我的规则,然后再将其提供给eval()。
在eval()中使用之前,应始终针对json语法测试json字符串。所以json字符串"{foo:alert('XSS')}"不会通过,因为"alert('XSS')"不是一个合适的值。
或者当环境安全时。
但是当你使用易受中间人攻击影响的协议时,你真的可以信任这个来源吗?
好吧,然后使用HTTPS。 OTOH:中间人不是花园种类网络应用程序的典型攻击场景,而跨站点脚本则是。
eval 也无法正确解析所有有效的JSON字符串。例如JSON.parse('"\u2028" ') ==="\u2028" 但eval('"\u2028" ') 引发异常,因为U + 2028是JavaScript中的换行符,但就JSON而言它不是换行符。
@Justin - 如果协议受到损害,那么通常初始页面加载将通过相同的协议发送,然后这是一个没有实际意义的点,因为客户端已经尽可能地受到损害。
精美地说@Tomalak,我现在在答案中提到了这一点!真棒!
"在JSON的情况下,它或多或少难以篡改源,因为它来自您控制的Web服务器。"除非您在nodejs中构建REST API服务。即使您处于控制之中,一旦受信任的服务器碰巧受到损害,您就会引入一个漏洞,使其成为"安全"用户会话的理想基石。黑客在这种天真中茁壮成长。幸运的是,现在eval 有很好的替代方案。
Node.js或服务器端的其他东西绝对没有。做它。节点中没有固有的漏洞。当您的服务器遭到入侵时,无论您使用的是JSON还是其他任何东西都是无关紧要的,因此您的论点有点循环。
让我们真正的人:
现在每个主要的浏览器都有一个内置的控制台,你可能会被黑客大量使用来调用任何有价值的函数 - 为什么他们会费心去使用eval语句 - 即使它们可以?
如果编译2000行JavaScript需要0.2秒,如果我评估四行JSON,我的性能会下降吗?
即使是克罗克福德对"eval is evil"的解释也很薄弱。
eval is Evil, The eval function is the most misused feature of
JavaScript. Avoid it
正如克罗克福德本人可能会说的那样"这种说法往往会产生非理性的神经症。不要买它。"
了解eval并了解它何时可能有用更为重要。例如,eval是评估软件生成的服务器响应的合理工具。
BTW:Prototype.js直接调用eval五次(包括evalJSON()和evalResponse())。 jQuery在parseJSON中使用它(通过Function构造函数)。
如果可用,JQuery使用浏览器的内置JSON.parse函数(速度更快,更安全),仅使用eval作为回退机制。"eval is evil"这句话是一个相当好的指导方针。
重新"每个主要的浏览器现在都有一个内置的控制台......"。当一个用户可以输入然后在另一个用户的浏览器中运行的代码时,代码注入是一个问题。浏览器控制台本身不允许一个用户在另一个用户浏览器中运行代码,因此在决定是否值得防止代码注入时它们是无关紧要的。
"现在每个主流浏览器都有一个内置的控制台...为什么他们会费心去使用eval语句?" - 你离开了标记。我建议你编辑答案。一个用户注入可以在另一个浏览器中运行的代码的能力是一个主要问题。这就是你需要变得真实的地方。
无论如何,谁是克罗克福德?你是对的,攻击者可以使用任何HTTP浸出工具来模仿浏览器并做任何事情,他不需要EVAL。
@akkishore,如果你想出一个支持你过度陈述的现实生活中的例子,我将不胜感激。
@AkashKava DNS毒药/ MITM,拦截&amp;编辑eval()ed数据和ka boom!
@akkishore,这与EVAL无关,这意味着你没有保护你的DNS或代理或其他任何东西,记住更多的浏览器,攻击者有很多工具可以伤害除EVAL以外的东西,写这样的话并不能证明什么,告诉我一个工作代码,这在EVAL中是邪恶的,在任何安全的DNS上执行。如果浏览器或客户端的机器受到损害,EVAL仍然不是邪恶的。
@AkashKava让我们简单一点。您是否建议我们设计我们的API /接口以接受可执行代码作为输入而无需进行健全性检查?对于那些说您可以使用Console来调用任何类型的函数的人,请注意,控制台可能无法使用eval'ed代码可用的闭包!
@akkishore,它对浏览器有什么害处?是的,如果它在服务器端代码,如服务器上的php或ruby或服务器上的c#,那么是的,必须检查安全性。让我们说一下我在这个评论框中输入的内容将被评估,它会对堆栈溢出服务器造成什么危害?没有。这是您的服务器端代码需要安全,浏览器无论如何都是高度安全的,因为它不提供任何形式的任何本机连接。一般来说,外部沙箱上的EVAL是邪恶的,但在沙盒浏览器中,它没有任何害处。
@AkashKava,我认为这里的其他人已经暗示了它,但是eval确实是一个问题。跨站点脚本(XSS)攻击是攻击者使JS代码在另一个用户的浏览器的上下文中运行的地方。他们可能会想到,他们可以做些什么呢?他们可以窃取您的会话并在该网站上冒充您。他们可以发布垃圾评论。他们可以收集您的个人信息。想象一下,这发生在银行网站上:他们可以窃取您的帐号和余额。我建议你阅读en.wikipedia.org/wiki/Cross-site_scripting。
@BrianDonovan现在怎么可能得到满足?哪个浏览器允许您在其他域的上下文中运行js。文章是历史,http只有Cookie隐藏会话&amp;来自js的饼干。所有主流浏览器都能很好地保护私人信息点是小知识更危险。您可能不会使用EVAL&amp;不要将http仅应用于更有害的cookie。不使用EVAL不会解决任何问题,无论EVAL如何,您的服务器安全性都应该很严格。
@AkashKava,服务器安全很重要,但它不是故事的唯一部分。此外,我们不是在谈论在另一个域的上下文中运行代码,我们讨论的是将HTML注入到同一域上的另一个用户的浏览器中。例如,如果您运行的网站允许人们使用HTML的子集发布评论,则必须非常小心,不要像这样允许HTML: 。这并不简单。如果你允许HTML在另一个用户的浏览器中运行,那么攻击者可以做坏事,正如我在上一篇评论中提到的那样。
@AkashKava你没有意识到的是,如果我在我的评论框中提交javascript,那javascript就会进入数据库。当另一个用户查看该注释(我将javascript放入其中)时,eval会在呈现时使用该javascript,并使用解释器对其进行评估,从而导致我的嵌入式javascript在其他用户的浏览器上执行。通过这样做,我可以收集各种信息。他们的用户名,他们在数据库中的用户ID,他们的电子邮件地址等。这不是一个难的答案,如果你有谷歌搜索XSS,你会在大约10秒内看到为什么这是一个问题。
这个答案是如此令人难以置信的错误,我感到震惊,它有任何赞成。 Eval JSON?你疯了吗?有没有听说过解析器或代码注入?
@KyleRichter,就在那里,当JavaScript进入数据库时??,这是您的弱服务器端安全性的完美示例。攻击者可以轻松使用除浏览器之外的任何其他内容,即使简单的curl 可以将JavaScript发送到数据库中。它不是eval 是危险的,它是你的弱安全性,允许代码进入数据库,这会导致所有问题,顺便说一句,攻击者即使没有eval 也可以做到。
@AkashKava我不知道为什么我甚至会通过回应来尊重这一点,但我是。字符串中的Javascript本身并不是有害的,但使用eval会导致javascript运行,否则它将被解释为字符串,不会被解析。我并不反对应该进行服务器端转发,但是,使用eval只是要求某人找到一种方法来利用该字段。无论你如何论证这一点,它都会带来安全风险,这是一种不好的做法。期。这就是为什么这里的每个人都在回应我所说的不使用eval的原因。
@AkashKava还有一件事。当且仅当您可以保证唯一可能的输入是您的应用程序生成的javascript时,eval()非常有用。即使这样,它也只是有用,因为没有更好的选项。 Prototype.js使用了eval,因为它是他们唯一可用于他们需求的东西,并且他们在他们知道代码完整性纯净的地方做到了。
这个答案忽略了跨站点脚本的整个概念。
我倾向于遵循Crockford对eval() 的建议,并完全避免它。即使看起来需要它的方式也没有。例如,setTimeout() 允许您传递函数而不是eval。
1 2 3
setTimeout( function ( ) {
alert( 'hi' ) ;
} , 1000 ) ;
即使它是一个受信任的来源,我也不会使用它,因为JSON返回的代码可能会出现乱码,最多可能会做一些不好的事情,最坏的情况是暴露出坏事。
如何成功调用Web服务器会产生乱码结果(尽管JSON生成Web服务器代码中存在错误)?
我认为服务器端的JSON格式化程序中的错误肯定是个问题。服务器的响应是否依赖于任何类型的用户提交的文本?然后你得关注XSS。
如果您的网络服务器未通过HTTPS进行身份验证,那么您可能遭受某种中间人攻击,其中另一台主机拦截请求并发送自己的数据。
如果某人可以执行中间人攻击,他可以轻松地向您的脚本注入任何内容。
你根本不应该依赖你的javascript代码...你不要依赖在客户端运行的任何东西...如果有人做中间人攻击他为什么会搞乱你的json对象?他可以为您和不同的js文件提供不同的网页...
我个人不喜欢"总有其他方法可以做到这一点"。例如,您还可以说总是有办法避免面向对象的编程。这并不意味着它不是一个很好的选择。如果您了解eval及其危险性,它可以成为在正确情况下使用的一个很好的工具。
如何在没有eval 的情况下在w3schools,Stack Snippets等上编写类似"Tryit"编辑器的内容?
在Chrome(v28.0.1500.72)中进行调试时,我发现如果变量未在生成闭包的嵌套函数中使用,则它们不会绑定到闭包。我猜,这是JavaScript引擎的优化。
但是:当在导致闭包的函数内部使用eval() 时,外部函数的所有变量都绑定到闭包,即使它们根本不被使用。如果有人有时间测试是否可以产生内存泄漏,请在下面给我留言。
这是我的测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
( 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); 中)时,当expression 引用应该属于闭包的变量时,expression 的求值可能会失败,但是其实不是。
Eval是编译的补充,用于模板化代码。通过模板我的意思是你编写一个简化的模板生成器,生成有用的模板代码,提高开发速度。
我编写了一个框架,开发人员不使用EVAL,但他们使用我们的框架,反过来,框架必须使用EVAL生成模板。
使用以下方法可以提高EVAL的性能;而不是执行脚本,您必须返回一个函数。
它应该被组织为
1 2 3
var f = eval( "(function(a,b) { return a + b; })" ) ;
var a = f( 3 , 5 ) ;
缓存f肯定会提高速度。
此外,Chrome还可以轻松调试此类功能。
关于安全性,使用eval与否将几乎没有任何区别,
首先,浏览器在沙箱中调用整个脚本。
任何在EVAL中都是邪恶的代码,在浏览器本身都是邪恶的。攻击者或任何人都可以轻松地在DOM中注入脚本节点,并且如果他/她可以评估任何内容,则可以执行任何操作。不使用EVAL不会有任何区别。
主要是糟糕的服务器端安全性是有害的。服务器上的Cookie验证不佳或ACL实施不当会导致大多数攻击。
Java的本机代码中存在最近的Java漏洞等。 JavaScript曾经并且被设计为在沙箱中运行,而applet被设计为在具有证书等的沙箱之外运行,从而导致漏洞和许多其他事情。
编写用于模仿浏览器的代码并不困难。您所要做的就是使用您最喜欢的用户代理字符串向服务器发出HTTP请求。无论如何,所有测试工具都会模拟浏如果攻击者想要伤害你,EVAL是他们的最后手段。他们还有许多其他方法来处理您的服务器端安全性。
浏览器DOM无权访问文件而不能访问用户名。事实上,eval可以访问的机器上没有任何东西。
如果您的服务器端安全性足够强大,任何人都可以从任何地方进行攻击,那么您不必担心EVAL。正如我所提到的,如果EVAL不存在,攻击者可以使用许多工具来攻击您的服务器,而不管您的浏览器的EVAL功能如何。
Eval仅适用于生成一些模板,以根据事先未使用的内容进行复杂的字符串处理。例如,我更喜欢
1
"FirstName + ' ' + LastName"
相反
1
"LastName + ' ' + FirstName"
作为我的显示名称,它可以来自数据库而且不是硬编码的。
您可以使用函数而不是eval - function (first, last) { return last + ' ' + first } 。
列的名称来自数据库。
eval 的威胁主要是其他用户。假设您有一个设置页面,它可以让您设置名称对其他人的显示方式。我们还说你在编写时没有想清楚,所以你的选择框有像Last First</option> 这样的选项。我打开我的开发工具,将选项的value 更改为alert('PWNED!') ,选择更改的选项,然后提交表单。现在,任何时候其他人都可以看到我的显示名称,该代码运行。
@cHao,你所谈论的那个是服务器端安全性差的例子,服务器永远不应该接受可以在任何人的浏览器中作为代码执行的数据。再一次,您无法理解服务器端安全性差的概念。
如果您愿意,可以抱怨服务器端安全性,但eval 的重点是执行不属于您编写的脚本的代码。如果您不需要这样做的权力(并且您几乎从不这样做),避免eval 有助于解决整个类别的问题。如果您的服务器端代码不够完美,这是一件好事。
"如果您的服务器端安全性足够强大,任何人都可以从任何地方进行攻击,那么您不应该担心EVAL。"究竟为什么你应该担心。没有服务器是100%安全的。密码泄露,社会工程,苦涩的员工,安全漏洞。不足以搜查系统。但是,如果我只能更新数据库中的一条记录,我会选择字符串处理器的源表。潜在的XSS攻击!这就是黑客的工作方式。他们没有管理员密码。他们发现微小的弱点,其中没有任何真正的影响。但结合起来,它们可能足以造成一些真正的伤害。
我看到人们主张不使用eval,因为它是邪恶的,但是我看到同样的人动态地使用Function和setTimeout,所以他们在引擎盖下使用eval:D
顺便说一句,如果您的沙箱不够确定(例如,如果您正在使用允许代码注入的站点上工作),则eval是您的最后一个问题。安全性的基本规则是所有输入都是邪恶的,但是在JavaScript的情况下,即使JavaScript本身也可能是邪恶的,因为在JavaScript中你可以覆盖任何函数而你无法确定你是否正在使用真正的函数,所以,如果恶意代码在您之前启动,则您无法信任任何JavaScript内置函数:D
现在这篇文章的后记是:
如果你真的需要它(80%的时间不需要eval)并且你确定你正在做什么,只需使用eval(或更好的功能;)),闭合和OOP覆盖80/90%的可以使用其他类型的逻辑替换eval的情况,其余的是动态生成的代码(例如,如果您正在编写解释器)并且您已经说过评估JSON(这里您可以使用Crockford安全评估;))
正如Crockford本人所指出的,当前的Web浏览器具有内置函数JSON.parse。
微软解释了为什么eval()在IE博客上的浏览器速度慢,IE + JavaScript性能建议第2部分:JavaScript代码效率低下。
您应该使用eval()的唯一实例是您需要动态运行动态JS。我说的是你从服务器上异步下载的JS ......
... 10次中的9次你可以通过重构轻松避免这样做。
如今,还有其他(和更好的)从服务器异步加载JavaScript的方法:w3bits.com/async-javascript
如果您完全控制传递给eval 函数的代码,则可以使用它。
如果你可以完全控制你传递给eval 的内容,那么最大的问题就是,什么时候才能成为一个字符串而不是真正的JS?
@cHao例如,如果你有一个大型游戏应用程序(5-10MB Javascript),最好先构建一个简单的快速加载AJAX-Preloader(1kb),它加载大型主脚本,同时显示一个加载 - 酒吧或类似的东西。下载后,您可以使用"eval(source)"或更好的"new Function(source)"来运行加载的Game-Application-Script。这样,用户可以直观地看到应用程序需要时间下载,直到游戏可以开始。如果没有这个,用户必须等待整个应用程序加载而没有任何视觉反馈。
@SammieFox还有其他(和更好的)方法,最值得注意的是 。另请参阅:w3bits.com/async-javascript
答案是危险的建议;太多的开发人员有一种虚假的控制感。对于不再积极维护的软件,该建议确实有意义。但是这样的软件应该被认为是死的。
eval 很少是正确的选择。虽然可能有许多实例可以通过将脚本连接在一起并动态运行来完成您需要完成的任务,但您通常可以使用更强大和可维护的技术:关联数组表示法(obj["prop"] 是与obj.prop 相同,闭包,面向对象技术,功能技术 - 改为使用它们。
我认为任何eval案例都是罕见的。你更有可能使用它认为它是合理的,而不是你在实际证明合理时使用它。
安全问题最为人所知。但也要注意JavaScript使用JIT编译,这与eval的效果非常差。 Eval有点像编译器的黑盒子,JavaScript需要能够提前预测代码(在某种程度上),以便安全,正确地应用性能优化和范围。在某些情况下,性能影响甚至会影响eval之外的其他代码。
如果你想了解更多:
https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch2.md#eval
在服务器端,eval在处理外部脚本(如sql或Influxdb或mongo)时非常有用。可以在不重新部署服务的情况下在运行时进行自定义验证。
例如,具有以下元数据的成就服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
{
"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"}`"
}
}
然后允许,
这个的结论:
如果没有经过全面测试,可能是代码中的错误并破坏了服务中的内容。
如果黑客可以在你的系统上编写脚本,那么你几乎搞砸了。
验证脚本的一种方法是将脚本的哈希保存在安全的位置,以便在运行之前检查它们。
尼斯。当我问这个问题时,我甚至没有考虑过服务器端的JS。
就客户端脚本而言,我认为安全问题是一个没有实际意义的问题。加载到浏览器中的所有内容都会受到操纵,因此应予以对待。当有更简单的方法来执行JavaScript代码和/或操作DOM中的对象(例如浏览器中的URL栏)时,使用eval()语句没有任何风险。
1
javascript: alert( "hello" ) ;
如果有人想操纵他们的DOM,我会说摆脱。防止任何类型的攻击的安全性应始终是服务器应用程序的责任期。
从务实的角度来看,在可以以其他方式完成任务的情况下使用eval()没有任何好处。但是,有一些特殊情况应该使用eval。如果是这样的话,绝对可以毫无风险地炸毁页面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
< 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] + "
" ;
}
}
outputEl.value = output;
}
< body>
</ html>
Re"当有更简单的方法来执行javascript和/或操作DOM中的对象时,使用eval()语句没有任何风险"。当一个用户可以输入然后在另一个用户的浏览器中运行的代码时,代码注入是一个问题。浏览器控制台本身不允许一个用户在另一个用户浏览器中运行代码,因此在决定是否值得防止代码注入时它们是无关紧要的。
是不是</head> ,即使是空的?
这个答案完全忽略了XSS的风险。
如果真的需要eval不是邪恶的。但是我不需要99.9%的eval使用(不包括setTimeout的东西)。
对我来说,邪恶不是表演,甚至不是安全问题(嗯,间接是两者兼而有之)。 eval的所有这些不必要的使用增加了维护地狱。重构工具被抛弃了。搜索代码很难。这些遗嘱的意外影响很大。
setTimeout不需要eval。您也可以在那里使用函数引用。
什么时候JavaScript的eval()不是邪恶的?
我总是试图阻止使用eval。几乎总是,提供更清洁和可维护的解决方案。即使对于JSON解析,也不需要Eval。 Eval增加了维护地狱。不是没有理由,道格拉斯克罗克福德这样的大师不赞成这种说法。
但我找到了一个应该使用它的例子:
当你需要传递表达式时。
例如,我有一个为我构造一般google.maps.ImageMapType 对象的函数,但我需要告诉它配方,如何从zoom 和coord 参数构造tile URL:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
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() - tileURLexpr只是一个模板,所以明智地使用replace()就可以完成这项任务。尽管如此,它确实让我想起了我提交问题时的一个例子,这与允许用户指定要评估的数学公式有关,类似于电子表格功能。当然我当时没有提到,因为我不想影响答案!
tileURL: function (zoom, coord) { return 'http://tile.openstreetmap.org/' + b + '/' + a.x + '/' + a.y + '.png'; },
只要您可以确定代码的来源来自您或实际用户,就没有理由不使用eval()。即使他可以操纵发送到eval()函数的内容,这也不是安全问题,因为他能够操纵网站的源代码,因此可以更改JavaScript代码本身。
那么......何时不使用eval()?只有在第三方有可能改变它时才应使用Eval()。就像拦截客户端和服务器之间的连接一样(但如果这是一个问题,请使用HTTPS)。你不应该使用eval()来解析其他人在论坛中编写的代码。
重新"没有理由不使用eval(),只要您可以确定代码的来源是来自您或实际用户。"这假设有一个用户。该前提未在OP中说明。当有多个用户时,由一个用户的内容组成的字符串的粗心eval 可以允许该用户在另一个用户的浏览器中执行代码。
@MikeSamuel,eval可以在其他用户的浏览器中执行代码,我没有听说过,你试过这个吗?这在浏览史上从未发生过,你能告诉我们一个例子吗?
@AkashKava,一个字符串可以源于一个用户代理,存储在数据库中,然后提供给另一个eval 的浏览器。它一直在发生。
@MikeSamuel数据库?哪里?谁服务错误的字符串?不是服务器端的数据库怪吗?首先,EVAL不应该因编写糟糕的服务器端代码而受到指责。使用jsfiddle并向世界展示它可能造成伤害的真实世界示例。
@AkashKava,我不明白你的问题。我们不是在讨论特定的应用程序,而是不使用eval 的原因。如何责备服务器有用吗?如果有人应该受到指责,那应该是攻击者。无论责任如何,尽管服务器中存在漏洞,但不易受XSS攻击的客户端比易受攻击的客户端更好,其他条件相同。
@AkashKava你可能需要eval 来制作jsfiddle。
"没有理由......"不正确。这个答案忽略了性能和可维护性。
我使用eval :import的例子。
它通常如何完成。
1 2 3 4 5 6
var components = require( 'components' ) ;
var Button = components.Button ;
var ComboBox = components.ComboBox ;
var CheckBox = components.CheckBox ;
...
// That quickly gets very boring
但是在eval 和一个小帮助函数的帮助下,它可以获得更好的外观:
1 2
var components = require( 'components' ) ;
eval( importable( 'components' , 'Button' , 'ComboBox' , 'CheckBox' , ...) ) ;
importable 可能看起来像(此版本不支持导入具体成员)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
function importable( path) {
var name;
var pkg = eval( path) ;
var result = '
' ;
for ( name in pkg) {
result += 'if (name !== undefined) throw"import error: name already exists";
' .replace ( /name/g , name) ;
}
for ( name in pkg) {
result += 'var name = path.name;
' .replace ( /name/g , name) .replace ( 'path' , path) ;
}
return result;
}
+1的想法,但你有一个错误:.replace(/name/g, name).replace('path', path) 。如果name 包含字符串"path" ,那么您可能会感到意外。
为components 的每个属性声明一个变量是一种可能的代码气味;重构代码可能会完全消除"问题"。你目前的解决方案只是语法糖。如果您坚持这样做,那么我建议您编写自己的预处理器,以便在部署之前执行。这应该使eval 远离生产代码。
仅在测试期间,如果可能的话。另请注意,eval()比其他专门的JSON等评估程序慢得多。
当您没有宏时,Eval对于代码生成很有用。
对于(一个愚蠢的)示例,如果您正在编写Brainfuck编译器,您可能希望构造一个以字符串形式执行指令序列的函数,并对其进行评估以返回函数。
要么编写一个编译器(保存而不是执行正在生成的代码),要么编写一个解释器(每个指令都有一个预编译的实现)。 eval 的用例也不是。
如果您生成了javascript代码并希望立即执行它(比如直接解释的性能优势),那将是eval的一个用例。
好点子;我在这篇文章中看到了一个关于Blockly的例子。我很震惊谷歌推荐eval ,当替代(功能)更快(如MDN中所解释)更可靠(通过更好地隔离生成的代码和同一网页上的其他"支持"代码来防止不可预测的错误) 。
我不知道功能到现在为止,谢谢。
代码生成。我最近写了一个名为Hyperbars的库,它弥合了虚拟dom和把手之间的差距。它通过解析把手模板并将其转换为hyperscript来实现。 hyperscript首先作为字符串生成,然后在返回之前,eval() 将其转换为可执行代码。我在这种特殊情况下发现eval() 与邪恶完全相反。
基本上来自
1 2 3
{ { #each names} }
< span> { { this } } </ span>
{ { / each} }
对此
1 2 3 4 5 6 7
( 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() 的性能在这种情况下也不是问题,因为您只需要解释生成的字符串一次,然后多次重复使用可执行输出。
如果您对此感到好奇,可以看看代码生成是如何实现的。
"超文本首先作为字符串生成(...)"在构建阶段完成所有代码生成更有意义,将生成的超文本代码写入单独的可执行文件(.js),然后将该文件部署到测试和生产。我喜欢你使用代码生成的方式。只是eval 是一个暗示,属于编译时的一些责任已经进入运行时。
我相信eval对于客户端Web应用程序来说是一个非常强大的功能并且安全......像JavaScript一样安全,但不是。 :-)安全问题本质上是服务器端问题,因为现在,使用像Firebug这样的工具,您可以攻击任何JavaScript应用程序。
eval 的使用需要针对XSS攻击进行保护,这并不总是很容易实现。
当您使用解析函数(例如,jQuery.parseJSON)解析JSON结构时,它需要JSON文件的完美结构(每个属性名称都是双引号)。但是,JavaScript更灵活。因此,您可以使用eval()来避免它。
不要盲目使用eval ,尤其是从第三方源获取JSON数据时。请参阅JSON.Stringify,不带属性引号?正确的方法来解析"没有引用键名称的JSON"。
如果它不在属性名称周围使用双引号,则它可能是对象文字的字符串表示形式,但它不是JSON。 JSON将属性名称定义为string ,并使用反斜杠转义将string 定义为零个或多个Unicode字符的序列,用双引号括起来。
参见Nikolas Zakas的文章 -"eval()不是邪恶的,只是误解了"nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood
@vitmalina来自Zakas的文章:"如果您正在接受用户输入并通过eval()运行它,这可能会很危险。但是,如果您的输入不是来自用户,那么真的有危险吗?"这正是问题所在。一旦你的代码超出"hello world"比例,很快就无法证明你没有将用户输入泄露到eval 中。在任何严肃的多租户Web应用程序中,有许多开发人员在相同的代码库上工作,这是不可接受的。