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} )