当前位置:  开发笔记 > 编程语言 > 正文

为什么要避免使用exec()和eval()?

如何解决《为什么要避免使用exec()和eval()?》经验,为你挑选了7个好方法。

我在多个地方多次看过这个,但从来没有找到令人满意的解释,为什么会出现这种情况.

所以,希望有人会在这里提出.为什么我们(至少一般)不使用exec()eval()

编辑:我看到人们假设这个问题与网络服务器有关 - 它没有.我可以看到为什么传递给unsanitized的字符串exec可能不好.在非网络应用程序中它是坏的吗?



1> RossFabrican..:

通常有更清晰,更直接的方法来获得相同的效果.如果您构建一个复杂的字符串并将其传递给exec,则代码很难遵循,并且难以测试.

示例:我编写的代码读取字符串键和值,并在对象中设置相应的字段.它看起来像这样:

for key, val in values:
    fieldName = valueToFieldName[key]
    fieldType = fieldNameToType[fieldName]
    if fieldType is int:
        s = 'object.%s = int(%s)' % (fieldName, fieldType) 
    #Many clauses like this...

exec(s)

对于简单的情况,该代码并不太可怕,但随着新类型的出现,它变得越来越复杂.当有错误时,他们总是在调用exec时触发,因此堆栈跟踪并没有帮助我找到它们.最后,我切换到一个稍微长一点,不那么聪明的版本,明确地设置每个字段.

代码清晰度的第一条规则是,通过仅查看附近的行,您的代码的每一行都应该易于理解.这就是为什么不鼓励使用goto和全局变量的原因.exec和eval可以很容易地破坏这个规则.


它不是一个稻草人.将文字传递给执行官有什么意义?至于你的其他评论.我输入了一些快速代码来说明一点,希望它可以解决我的观点,并且很容易看出这样的情况会变得更加复杂.确实,我的Python技能有点生疏,但这与我的观点没什么关系.

2> bobince..:

当你需要exec和eval时,是的,你确实需要它们.

但是,这些函数的大多数野外使用(以及其他脚本语言中的类似结构)是完全不合适的,可以用更快,更安全和更少错误的其他更简单的结构替换.

通过适当的转义和过滤,您可以安全地使用exec和eval.但那种直接寻求执行/解决问题的程序员(因为他们不了解语言提供的其他设施)并不是那种能够正确处理这种处理的编码器; 它将是一个不理解字符串处理并且盲目地连接子字符串的人,导致脆弱的不安全代码.

这是弦乐的诱惑.投掷弦乐段看起来很容易,并且欺骗天真的编码人员认为他们理解他们正在做什么.但经验表明,在某些角落(或不是那么角落)的情况下,结果几乎总是错误的,通常具有潜在的安全隐患.这就是为什么我们说eval是邪恶的.这就是为什么我们说regex-for-HTML是邪恶的.这就是我们推动SQL参数化的原因.是的,你可以通过手动字符串处理得到所有这些东西......但除非你已经明白为什么我们说这些东西,否则你很可能不会.



3> Square Rig M..:

eval()和exec()可以促进延迟编程.更重要的是,它表示正在执行的代码可能未在设计时写入,因此未经过测试.换句话说,您如何测试动态生成的代码?特别是跨浏览器.


+1:"基本期望"是你拥有所有来源.使用exec()和eval()你不会 - 平凡 - 拥有*all*源.

4> Eli Bendersk..:

安全之余,evalexec经常被标记因为它们诱导复杂不可取.当你看到一个eval电话时,你经常不知道它背后的真实情况,因为它会影响通常在变量中的数据.这使得代码更难阅读.

调用解释器的全部功能是一个重武器,应该只保留用于非常棘手的情况.但是,在大多数情况下,最好避免使用更简单的工具.

也就是说,像所有概括一样,要警惕这一点.在某些情况下,exec和eval可能很有价值.但是你必须有充分的理由使用它们.有关一个可接受的用途,请参阅此帖



5> zzzeek..:

与大多数答案在这里所说的相反,exec实际上是在Python中构建超完备装饰器的配方的一部分,因为您可以精确复制有关装饰函数的所有内容,为文档等目的生成相同的签名.它是广泛使用的装饰器模块(http://pypi.python.org/pypi/decorator/)功能的关键.exec/eval必不可少的其他情况是构造任何类型的"解释Python"类型的应用程序,例如Python解析的模板语言(如Mako或Jinja).

因此,这些功能的存在并不是"不安全"应用程序或库的直接标志.以天真的javascripty方式使用它们来评估传入的JSON或其他东西,是的,这是非常不安全的.但与往常一样,它一切都在你使用它的方式,这些是非常重要的功能.



6> jathanism..:

eval()过去曾经(并且仍然不时地)用于在快速和肮脏的操作期间按摩数据.它是可用于完成工作的工具包的一部分,但绝不能用于您计划在生产中使用的任何内容,例如任何命令行工具或脚本,因为其他答案中提到了所有原因.

您无法相信您的用户 - 做正确的事情.在大多数情况下,他们会,但你必须期望他们做你从未想过的所有事情,并找到你从未想到的所有错误.这正是eval()从工具到责任的地方.

一个完美的例子就是使用Django构建一个QuerySet.传递给查询的参数接受关键字参数,如下所示:

results = Foo.objects.filter(whatever__contains='pizza')

如果您以编程方式分配参数,您可能会想要执行以下操作:

results = eval("Foo.objects.filter(%s__%s=%s)" % (field, matcher, value))

但总有一种更好的方法是不使用eval(),即通过引用传递字典:

results = Foo.objects.filter( **{'%s__%s' % (field, matcher): value} ) 

通过这种方式,它不仅性能更快,而且更安全,更Pythonic.

故事的道德启示?

使用eval()OK的小任务,测试,真正临时的事情,但糟糕的永久使用,因为那里几乎可以肯定总有更好的方式来做到这一点!



7> dmckee..:

在可能运行用户输入的上下文中允许这些功能是一个安全问题,实际工作的清理程序很难编写.


您是否信任命令行中的所有用户?也许你应该关注这个......
不可以.它们可以被用作权限升级攻击的一部分,这些人在计算机上没有root访问权限但有权运行脚本.
推荐阅读
无名有名我无名_593
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有