我正在编写一些JavaScript代码来解析用户输入的函数(用于类似电子表格的功能).解析了公式后,我可以 将其转换为JavaScript并eval()
在其上运行以产生结果.
但是,eval()
如果我可以避免它,我总是回避使用,因为它是邪恶的(而且,无论是对还是错,我一直认为它在JavaScript中更加邪恶,因为要评估的代码可能会被用户改变).
那么,什么时候可以使用它?
1> 小智..: 我想花一点时间来解决你的问题的前提 - eval()是" 邪恶的 ".编程语言人使用的" 邪恶 " 一词通常意味着"危险",或者更准确地说"能够通过简单的命令造成大量伤害".那么,什么时候可以使用危险的东西呢?当您知道危险是什么时,以及何时采取适当的预防措施.
至关重点,我们来看看使用eval()的危险性.可能存在许多小的隐患,就像其他一切一样,但两个大的风险 - eval()被认为是邪恶的原因 - 是性能和代码注入.
性能 - eval()运行解释器/编译器.如果你的代码是编译的,那么这是一个很大的问题,因为你需要在运行时调用一个可能很重的编译器.但是,JavaScript仍然主要是一种解释语言,这意味着在一般情况下调用eval()并不是一个很大的性能影响(但请参阅下面的具体说明).
代码注入 - eval()可能在提升的权限下运行一串代码.例如,以管理员/ root身份运行的程序永远不会想要eval()用户输入,因为该输入可能是"rm -rf/etc/important-file"或更糟.同样,浏览器中的JavaScript没有这个问题,因为程序无论如何都在用户自己的帐户中运行.服务器端JavaScript可能存在这个问题.
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.
至于性能,你将不得不重视编码的简易性.我认为,如果你正在解析公式,你也可以在解析期间计算结果,而不是运行另一个解析器(eval()中的一个).但是使用eval()进行编码可能更容易,并且性能损失可能不明显.看起来eval()在这种情况下并不比任何其他可以节省你一些时间的函数更邪恶.
您没有解决使用eval难以调试的代码问题
如果数据来自您的服务器以及您(开发人员)生成的内容,则使用eval()没有任何害处.真正的伤害正在贬低你所阅读的一切.你看到很多人说eval()是邪恶的,他们不知道为什么除了他们在某处读它.
如果您对用户的数据非常关注,则代码注入是javascript的一个非常严重的问题.注入的代码将(在浏览器中)运行,就像它来自您的网站一样,让它可以执行用户可以手动执行的任何类型的shenanigan.如果您允许(第三方)代码进入您的页面,它可以代表您的客户订购商品,或者更改他们的图片,或者他们可以通过您的网站做的任何事情.要非常小心.让黑客拥有你的客户就像让他们拥有你的服务器一样糟糕.
@Sean McMillan:我想相信你,但是如果有人要拦截你的服务器并将javascript转换为`eval()`,他们也可以首先改变页面的来源,并控制用户的信息...我没有看到差异.
重新"代码注入 - 再次,浏览器中的JavaScript没有这个问题","而且,如果你在浏览器中运行,那么代码注入是一个相当小的风险,我相信." 您是否建议在浏览器中注入代码不是问题?多年来,XSS一直是OWASP十大榜单中的前三名.
"浏览器中的JavaScript没有这个问题,因为程序无论如何都在用户自己的帐户中运行" - 这并不能完全解决使用eval的问题.如果一个用户输入的脚本是另一个用户的eval(),则会造成严重破坏.答案似乎并不关心这一点.
@MikeSamuel,XSS只有在你可以将代码注入_someone else的browser_时才有效("跨站点脚本(XSS)是一种计算机安全漏洞......它使攻击者能够将客户端脚本注入其他用户查看的网页中." [维基百科(http://en.wikipedia.org/wiki/Cross-site_scripting)).因此,如果您评估用户在同一页面上输入的代码,没有任何伤害,没有犯规.如果你允许访客留下未经授权的评论,你就会打开他们留下杜鹃蛋的大门.
@thirdender,是什么让你相信到达'eval`的字符串不包含由另一个用户控制的字符?原始问题从未声明电子表格只能由一个用户查看.
代码注入:涉及的风险金额取决于eval函数的使用方式.`eval("alert('hello')")`没有比'alert('hello')更多的风险,因为在这两种情况下攻击者都需要改变源来改变任何东西.但是,如果像eval这样的东西("users [""+ username +"']")可能会非常危险,因为攻击者只需要设计一个聪明的用户名,他们就可以代表其他用户运行代码.tl;博士`eval`并不邪恶.`eval` +糟糕的节目是邪恶的.
2> Shog9..: eval()
不是邪恶的.或者,如果是这样,它就像反射,文件/网络I/O,线程和IPC在其他语言中是"邪恶的"一样是邪恶的.
如果出于您的目的 ,eval()
比手动解释更快,或者使您的代码更简单或更清晰......那么您应该使用它.如果不是,那么你不应该.就那么简单.
其中一个目的可能是生成优化的代码,这些代码要么太长也不能重复,无法手动编写.LISP中的那种东西会调用宏.
这是一般性的建议,它可以应用于字面上存在的任何代码块.它真的没有为这个问题添加任何东西; 特别是,来到这里的任何人都无法确定他们的特定用途是否有问题.
3> Tomalak..: 当你信任来源时.
在JSON的情况下,它或多或少难以篡改源,因为它来自您控制的Web服务器.只要JSON本身不包含用户上传的数据,使用eval就没有主要缺点.
在所有其他情况下,我会竭尽全力确保用户提供的数据符合我的规则,然后再将其提供给eval().
在eval()中使用之前,应始终针对json语法测试json字符串.所以json字符串"{foo:alert('XSS')}"不会通过,因为"alert('XSS')"不是一个合适的值.
`eval`也无法正确解析所有有效的JSON字符串.例如``JSON.parse('"\ u2028"')==="\ u2028"`但是`eval('"\ u2028"')引发异常,因为U + 2028是JavaScript中的换行符,但它不是就JSON而言是一个换行符.
好吧,然后使用HTTPS.OTOH:中间人不是花园种类网络应用程序的典型攻击场景,而跨站点脚本则是.
4> plodder..: 让我们真正的人:
现在每个主流浏览器都有一个内置的控制台,你可能会被黑客大量使用来调用任何有价值的函数 - 为什么他们会费心去使用eval语句 - 即使它们可以?
如果编译2000行JavaScript需要0.2秒,如果我评估四行JSON,我的性能会下降吗?
即使是克罗克福德对"eval is evil"的解释也很薄弱.
eval是Evil,eval函数是JavaScript最被滥用的功能.躲开它
正如克罗克福德本人可能会说的那样"这种说法往往会产生非理性的神经症.不要买它."
了解eval并了解它何时可能有用更为重要.例如,eval是评估软件生成的服务器响应的合理工具.
BTW:Prototype.js直接调用eval五次(包括evalJSON()和evalResponse()).jQuery在parseJSON中使用它(通过Function构造函数).
重新"每个主要的浏览器现在都有一个内置的控制台......".当一个用户可以输入然后在另一个用户的浏览器中运行的代码时,代码注入是一个问题.浏览器控制台本身不允许一个用户在另一个用户浏览器中运行代码,因此在决定是否值得防止代码注入时它们是无关紧要的.
"现在每个主流浏览器都有一个内置的控制台......为什么他们会费心去使用eval语句?" - 你离开了标记.我建议你编辑答案.一个用户注入可以在另一个浏览器中运行的代码的能力是一个主要问题.这就是你需要变得真实的地方.
JQuery使用浏览器的内置JSON.parse函数(如果可用的话更快更安全),仅使用eval作为回退机制."eval is evil"这句话是一个相当好的指导方针.
@AkashKava你没有意识到的是,如果我在我的评论框中提交javascript,那javascript就会进入数据库.当另一个用户查看该注释(我将javascript放入其中)时,eval会在呈现时使用该javascript,并使用解释器对其进行评估,从而导致我的嵌入式javascript在其他用户的浏览器上执行.通过这样做,我可以收集各种信息.他们的用户名,他们在数据库中的用户ID,他们的电子邮件地址等.这不是一个难的答案,如果你有谷歌搜索XSS,你会在大约10秒内看到为什么这是一个问题.
@akkishore,如果你想出一个支持你陈述的陈述的真实例子,我将不胜感激.
这个答案忽略了跨站点脚本的整个概念。
无论如何,谁是克罗克福德?你是对的,攻击者可以使用任何HTTP浸出工具来模仿浏览器并做任何事情,他不需要EVAL.
@akkishore,这与EVAL无关,这意味着你没有保护你的DNS或代理或其他什么,记住更多的浏览器,攻击者有很多工具可以伤害除EVAL以外的东西,写这样的话并不能证明什么,给我看看工作代码,这在EVAL中是邪恶的,在任何安全的DNS上执行.如果浏览器或客户端的机器受到损害,EVAL仍然不是邪恶的.
@AkashKava,服务器安全很重要,但它不是故事的唯一部分.另外,我们不是在谈论在另一个域的上下文中运行代码,我们讨论的是将HTML注入到同一域*上的另一个用户的浏览器*中.例如,如果您运行一个允许人们使用HTML子集发布评论的网站,您必须非常小心,不要像这样允许HTML:`
`.这并不简单.如果你允许HTML在另一个用户的浏览器中运行,那么攻击者可以做坏事,正如我在上一篇评论中提到的那样.
@AkashKava,我想这里的其他人都在暗示它,但是评估确实是一个问题。跨站点脚本(XSS)攻击是攻击者导致JS代码在另一个用户浏览器的上下文中运行的地方。您可能会想,他们可以做什么?他们可以窃取您的会话并在该站点上冒充您。他们可以发布垃圾评论。他们可以收集您的个人信息。想象一下,这是在银行网站上发生的:他们可以窃取您的帐号和余额。我建议您阅读https://en.wikipedia.org/wiki/Cross-site_scripting。
@AkashKava我不知道为什么我什至要以回应来端庄,但我是。字符串中的Java脚本本身并没有害处,但是使用eval会使javascript运行,而否则它将被解释为字符串,而不会被解析。我不同意应该进行服务器端转义,但是,使用eval只是向某人寻求一种利用该领域的方法。无论您如何争论,它都确实会带来安全风险,并且是一种不良做法。期。这就是为什么这里的每个人都在回应我关于不使用eval的说法。
5> swilliams..: 我倾向于遵循克罗克福德的意见为eval()
,并完全避免.即使看起来需要它的方式也没有.例如,setTimeout()
允许您传递函数而不是eval.
setTimeout(function() {
alert('hi');
}, 1000);
即使它是一个值得信赖的 来源,我也不会使用它,因为JSON返回的代码可能会出现乱码,最多可能会做一些不好的事情,最坏的情况是暴露出坏事.
如果某人可以执行中间人攻击,他可以轻松地向您的脚本注入任何内容.
你根本不应该依赖你的javascript代码......你不要依赖在客户端运行的任何东西......如果有人做了中间人攻击,为什么他会搞乱你的json对象?他可以为您和不同的js文件提供不同的网页...
我个人不喜欢"总有其他方法可以做到这一点".例如,您还可以说总是有办法避免面向对象的编程.这并不意味着它不是一个很好的选择.如果您了解eval及其危险性,它可以成为在正确情况下使用的好工具.
如果您的网络服务器未通过HTTPS进行身份验证,那么您可能遭受某种中间人攻击,其中另一台主机拦截请求并发送自己的数据.
我认为服务器端的JSON格式化程序中的错误肯定是个问题.服务器的响应是否依赖于任何类型的用户提交的文本?然后你得关注XSS.
推荐阅读
如何解决《OmniSharp无法在VisualStudioCode中启动》经验,为你挑选了1个好方法。 ...
[详细]
如何解决《突出显示当前的UICollectionViewCelltvOS》经验,为你挑选了1个好方法。 ...
[详细]
如何解决《Flink:写入dev/null》经验,为你挑选了1个好方法。 ...
[详细]
如何解决《如何将css::before伪元素排成一个网格》经验,为你挑选了1个好方法。 ...
[详细]
如何解决《RubyonRails-Base64的外部图像URL》经验,为你挑选了1个好方法。 ...
[详细]
如何解决《未捕获的TypeError:无法读取未定义的属性"createRouteFromReactElement"》经验,为你挑选了1个好方法。 ...
[详细]
如何解决《如何为python3配置spacemacs?》经验,为你挑选了1个好方法。 ...
[详细]
如何解决《SeleniumWebdriver和SoapUI有什么区别?》经验,为你挑选了1个好方法。 ...
[详细]
如何解决《data.table中的扩展窗口(累积计算):如何提高性能》经验,为你挑选了1个好方法。 ...
[详细]
如何解决《如何按排序顺序获取重叠范围的计数?》经验,为你挑选了0个好方法。 ...
[详细]
如何解决《大熊猫图中单条线的访问和更改特征》经验,为你挑选了1个好方法。 ...
[详细]
如何解决《使用DateTime::Format::Strptime移动时区》经验,为你挑选了1个好方法。 ...
[详细]
如何解决《设计valid_password的奇怪问题?》经验,为你挑选了0个好方法。 ...
[详细]
如何解决《一次按下按钮后,如何使按钮变灰并禁用它?》经验,为你挑选了0个好方法。 ...
[详细]
如何解决《Invoke-WebRequest设置超时》经验,为你挑选了1个好方法。 ...
[详细]
如何解决《SpringAutowired服务和控制器无法正常工作》经验,为你挑选了1个好方法。 ...
[详细]
如何解决《SwipeRefreshLayout阻止水平滚动的RecyclerView》经验,为你挑选了1个好方法。 ...
[详细]
如何解决《sparksql当前时间戳功能》经验,为你挑选了1个好方法。 ...
[详细]
如何解决《没有frameworkAssemblies,无法解决程序集引用问题》经验,为你挑选了3个好方法。 ...
[详细]
如何解决《Redux-为什么在根状态下加载状态》经验,为你挑选了1个好方法。 ...
[详细]