每次有人提到 eval(),每个人都说它存在“安全问题”,但没有人详细说明它们是什么。大多数现代浏览器似乎能够像调试普通代码一样调试 eval() ,人们声称性能下降的说法是可疑的/取决于浏览器。
那么,与 eval() 相关的问题(如果有的话)是什么?我还没有想出任何可以在 JavaScript 中使用 eval() 来利用的东西。(我确实看到服务器上的 eval()'ing 代码存在问题,但客户端 eval() 似乎是安全的。)
每次有人提到 eval(),每个人都说它存在“安全问题”,但没有人详细说明它们是什么。大多数现代浏览器似乎能够像调试普通代码一样调试 eval() ,人们声称性能下降的说法是可疑的/取决于浏览器。
那么,与 eval() 相关的问题(如果有的话)是什么?我还没有想出任何可以在 JavaScript 中使用 eval() 来利用的东西。(我确实看到服务器上的 eval()'ing 代码存在问题,但客户端 eval() 似乎是安全的。)
eval()
将字符串作为代码执行。您使用eval()
正是因为事先不知道字符串内容,甚至是在服务器端生成的;基本上,您需要,eval()
因为 JavaScript 本身将从客户端中仅动态可用的数据生成字符串。
因此,eval()
在 JavaScript 代码将生成代码的情况下是有意义的。这本质上不是邪恶的,但很难安全地做到这一点。编程语言旨在允许人类编写计算机可以理解的指令;为此,任何语言都充满了小怪癖和应该帮助人类程序员的特殊行为(例如,在 JavaScript 中某些语句的末尾自动添加“;”)。对于“普通”编程来说,这一切都很好。但是,当您基于可能具有潜在恶意的数据(例如,来自其他站点用户的字符串摘录)从另一个程序生成代码时,作为代码生成器的开发人员,您必须了解所有 这些怪癖,并防止恶意数据以破坏性方式利用它们。
从这个意义上说,代码生成器(因此eval()
)会引发与原始 SQL 及其后果相同的概念问题,即SQL 注入攻击。在运行时从外部提供的参数组装 SQL 请求可以安全地完成,但这需要注意很多细节,所以通常的建议是不要这样做。这与通常的安全难题有关,即它是不可测试的:您可以测试某些代码是否在正确数据上正常工作,但并不是说它在不正确数据上永远不会不正常工作。同样,eval()
安全使用是可能的,但在实践中非常困难,因此不鼓励使用。
所有这些都是笼统地说。在您的特定情况下,eval()
可能是安全的。但是,要获得一个可以安全使用的上下文eval()
,实际上需要eval()
.
eval() 是跨站点脚本的可能向量。
在正常情况下,尝试 XSS 的攻击者可能希望<script></script>
通过任何可能存在的编码、过滤器或防火墙来获取脚本标签。如果 eval() 对用户输入进行操作,则无需脚本标记。
Eval 存在于许多恶意脚本中,因为它有助于混淆代码和/或将禁止的字符偷偷通过过滤器。因此,经常在用户输入中检查 eval()。因此,在使用 eval() 时,您可能会为攻击者提供他们必要的工具之一。我正在抢劫一家银行,我知道我不必将枪偷偷通过任何金属探测器,因为大楼内的伞架上有一堆。
正如其他人所解释的,可以使用 eval 动态创建代码,这使得更难理解程序的控制流。但是,我认为 eval 并不比在运行时生成代码的所有其他方法更邪恶,document.write(...)
比如object.innerHTML(...)
. 虽然这些主要用于更改程序的 DOM,但它们也用于插入新代码(即在代码中添加脚本语句,或带有一些 onXXXX 处理程序的新元素等)。
虽然 eval 经常用于攻击(XSS、恶意广告......)以规避过滤器或隐藏代码的真正目的,但它经常在那里以模糊的形式使用,即类似z='ev'; z+='al'; v=window; v[z]("alert(1)")
. 这意味着如果您只是尝试使用 eval 的显式调用来过滤代码,那么您并不安全,因为调用被混淆了,或者像 innerHTML 这样的“好”函数被用于不良目的。
除了这里提出的要点之外,我想澄清一下:您在使用 eval() 时基本上要处理的问题是必须回答以下问题:
如果您比攻击者更全面地考虑了这些问题,并且仍在考虑使用 eval(),那就去做吧。你可能会发现你已经厌倦了在你的开发生涯中思考这个问题,并开始在原则上避免使用它。