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

Python 为什么要避免exec()和eval()?,python,Python,我在多个地方多次看到这种情况,但从未找到令人满意的解释来解释为什么会出现这种情况 所以,希望这里会有一个。为什么我们(至少通常)不应该使用exec()和eval() 编辑:我看到人们认为这个问题与web服务器有关——事实并非如此。我可以理解为什么传递给exec的未初始化字符串可能是错误的。在非web应用程序中不好吗?允许这些功能在可能运行用户输入的上下文中运行是一个安全问题,而实际工作的清理程序很难编写。允许这些功能在可能运行用户输入的上下文中运行是一个安全问题,而实际工作的清理程序很难编写 s

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

所以,希望这里会有一个。为什么我们(至少通常)不应该使用
exec()
eval()


编辑:我看到人们认为这个问题与web服务器有关——事实并非如此。我可以理解为什么传递给
exec
的未初始化字符串可能是错误的。在非web应用程序中不好吗?

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

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

s = "import shutil; shutil.rmtree('/nonexisting')"
eval(s)
例如,现在假设有人可以从web应用程序控制s

不要尝试在计算机上执行此操作

例如,现在假设有人可以从web应用程序控制s


不要在你的计算机上尝试这样做同样的原因你不应该以root身份登录:这太容易让你自食其果。

同样的原因你不应该以root身份登录:这太容易让你自食其果。

原因#1:一个安全缺陷(即编程错误……我们不能声称这些是可以避免的)您刚刚授予用户访问服务器外壳的权限。

原因#1:一个安全缺陷(即编程错误……我们不能声称这些是可以避免的),而您刚刚授予用户访问服务器外壳的权限。

通常有更清晰、更直接的方法来获得相同的效果。如果构建一个复杂的字符串并将其传递给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)
这段代码对于简单的情况来说并不可怕,但随着新类型的出现,它变得越来越复杂。当出现bug时,它们总是在调用exec时触发,因此堆栈跟踪无法帮助我找到它们。最后,我切换到一个稍微长一点、不那么聪明的版本,该版本明确地设置了每个字段


代码清晰性的第一条规则是,代码的每一行都应该很容易理解,只需查看其附近的行即可。这就是为什么不鼓励使用goto和全局变量。exec和eval很容易严重违反这一规则。

通常有更清晰、更直接的方法来达到同样的效果。如果构建一个复杂的字符串并将其传递给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)
这段代码对于简单的情况来说并不可怕,但随着新类型的出现,它变得越来越复杂。当出现bug时,它们总是在调用exec时触发,因此堆栈跟踪无法帮助我找到它们。最后,我切换到一个稍微长一点、不那么聪明的版本,该版本明确地设置了每个字段


代码清晰性的第一条规则是,代码的每一行都应该很容易理解,只需查看其附近的行即可。这就是为什么不鼓励使用goto和全局变量。exec和eval很容易严重违反此规则。

在交互式解释器中尝试此操作,看看会发生什么:

>>> import sys
>>> eval('{"name" : %s}' % ("sys.exit(1)"))

当然,这是一个极端的情况,但要防止类似的事情发生可能很棘手。

在交互式解释器中尝试一下,看看会发生什么:

>>> import sys
>>> eval('{"name" : %s}' % ("sys.exit(1)"))

当然,这是一种极端情况,但要防止这种情况发生可能很棘手。

除了安全性之外,
eval
exec
通常被标记为不受欢迎,因为它们会导致复杂性。当您看到一个
eval
调用时,您通常不知道它背后到底发生了什么,因为它作用于通常位于变量中的数据。这使得代码更难阅读

调用解释器的全部功能是一个沉重的武器,应该只保留在非常棘手的情况下。然而,在大多数情况下,最好避免这种情况,并且应该使用更简单的工具


这就是说,像所有的概括一样,要警惕这一点。在某些情况下,exec和eval可能很有价值。但你一定有很好的理由使用它们。有关一种可接受的用途,请参见。

除了安全性之外,
eval
exec
通常被标记为不受欢迎,因为它们会导致复杂性。当您看到一个
eval
调用时,您通常不知道它背后到底发生了什么,因为它作用于通常位于变量中的数据。这使得代码更难阅读

调用解释器的全部功能是一个沉重的武器,应该只保留在非常棘手的情况下。然而,在大多数情况下,最好避免这种情况,并且应该使用更简单的工具

这就是说,像所有的概括一样,要警惕这一点。在某些情况下,exec和eval可能很有价值。但你一定有很好的理由使用它们。有关可接受的用法,请参阅。

eval()和exec()可以促进惰性编程。更重要的是,它表明正在执行的代码可能没有在设计时编写,因此没有经过测试。换句话说,如何测试动态生成的代码?尤其是跨浏览器。eval()和exec()可以促进惰性编程。更重要的是,它表明正在执行的代码可能没有在设计时编写,因此没有经过测试。换句话说,如何测试动态生成的代码?尤其是跨浏览器。

我过去(现在仍然不时)使用
eval()
在快速和肮脏的操作中处理数据。它是工具箱的一部分,可用于完成工作,但决不能用于生产中计划使用的任何东西,如任何命令行工具或脚本,因为
results = Foo.objects.filter( **{'%s__%s' % (field, matcher): value} )