python 为什么要避免使用 exec() 和 eval()?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1933451/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why should exec() and eval() be avoided?
提问by Isaac
I've seen this multiple times in multiple places, but never have found a satisfying explanation as to why this should be the case.
我在多个地方多次看到这种情况,但从未找到令人满意的解释,说明为什么会出现这种情况。
So, hopefully, one will be presented here. Why should we (at least, generally) not use exec()
and eval()
?
所以,希望这里能介绍一个。为什么我们(至少,一般来说)不应该使用exec()
and eval()
?
EDIT: I see that people are assuming that this question pertains to web servers –?it doesn't. I can see why an unsanitized string being passed to exec
could be bad. Is it bad in non-web-applications?
编辑:我看到人们假设这个问题与网络服务器有关 -?它不是。我可以exec
理解为什么传递给未经处理的字符串可能很糟糕。它在非网络应用程序中很糟糕吗?
采纳答案by RossFabricant
There are often clearer, more direct ways to get the same effect. If you build a complex string and pass it to exec, the code is difficult to follow, and difficult to test.
通常有更清晰、更直接的方法来获得相同的效果。如果构建一个复杂的字符串并将其传递给 exec,则代码很难遵循,也很难测试。
Example: I wrote code that read in string keys and values and set corresponding fields in an object. It looked like this:
示例:我编写了读取字符串键和值并在对象中设置相应字段的代码。它看起来像这样:
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)
That code isn't too terrible for simple cases, but as new types cropped up it got more and more complex. When there were bugs they always triggered on the call to exec, so stack traces didn't help me find them. Eventually I switched to a slightly longer, less clever version that set each field explicitly.
对于简单的情况,该代码并不太糟糕,但是随着新类型的出现,它变得越来越复杂。当出现错误时,它们总是在调用 exec 时触发,因此堆栈跟踪无法帮助我找到它们。最终我切换到一个稍长、不那么聪明的版本,它明确地设置了每个字段。
The first rule of code clarity is that each line of your code should be easy to understand by looking only at the lines near it. This is why goto and global variables are discouraged. exec and eval make it easy to break this rule badly.
代码清晰的第一条规则是,你的代码的每一行都应该很容易理解,只需查看靠近它的行。这就是不鼓励 goto 和全局变量的原因。exec 和 eval 可以很容易地严重破坏这条规则。
回答by bobince
When you need exec and eval, yeah, you really do need them.
当您需要 exec 和 eval 时,是的,您确实需要它们。
But, the majority of the in-the-wild usage of these functions (and the similar constructs in other scripting languages) is totally inappropriate and could be replaced with other simpler constructs that are faster, more secure and have fewer bugs.
但是,这些函数(以及其他脚本语言中的类似结构)的大部分在野外使用是完全不合适的,可以用其他更快、更安全且错误更少的更简单的结构代替。
You can, with proper escaping and filtering, use exec and eval safely. But the kind of coder who goes straight for exec/eval to solve a problem (because they don't understand the other facilities the language makes available) isn't the kind of coder that's going to be able to get that processing right; it's going to be someone who doesn't understand string processing and just blindly concatenates substrings, resulting in fragile insecure code.
通过适当的转义和过滤,您可以安全地使用 exec 和 eval。但是那种直接使用 exec/eval 来解决问题的编码器(因为他们不了解该语言提供的其他功能)并不是那种能够正确处理的编码器;这将是一个不了解字符串处理的人,只是盲目地连接子字符串,从而导致脆弱的不安全代码。
It's the Lure Of Strings. Throwing string segments around lookseasy and fools na?ve coders into thinking they understand what they're doing. But experience shows the results are almost always wrong in some corner (or not-so-corner) case, often with potential security implications. This is why we say eval is evil. This is why we say regex-for-HTML is evil. This is why we push SQL parameterisation. Yes, you canget all these things right with manual string processing... but unless you already understand why we say those things, chances are you won't.
这就是弦的诱惑。四处乱扔字符串段看起来很容易,而且会愚弄天真的编码人员以为他们了解自己在做什么。但经验表明,在某些角落(或不那么角落)的情况下,结果几乎总是错误的,通常具有潜在的安全隐患。这就是为什么我们说 eval 是邪恶的。这就是为什么我们说 regex-for-HTML 是邪恶的。这就是我们推动 SQL 参数化的原因。是的,您可以通过手动字符串处理来正确处理所有这些事情……但是除非您已经理解我们为什么说这些事情,否则您很可能不会。
回答by Square Rig Master
eval() and exec() can promote lazy programming. More importantly it indicates the code being executed may not have been written at design time therefore not tested. In other words, how do you test dynamically generated code? Especially across browsers.
eval() 和 exec() 可以促进惰性编程。更重要的是,它表明正在执行的代码可能不是在设计时编写的,因此没有经过测试。换句话说,您如何测试动态生成的代码?尤其是跨浏览器。
回答by Eli Bendersky
Security aside, eval
and exec
are often marked as undesirable because of the complexity they induce. When you see a eval
call you often don't know what's really going on behind it, because it acts on data that's usually in a variable. This makes code harder to read.
抛开安全性不谈,eval
并且exec
由于它们引起的复杂性通常被标记为不受欢迎。当您看到一个eval
调用时,您通常不知道它背后到底发生了什么,因为它作用于通常位于变量中的数据。这使得代码更难阅读。
Invoking the full power of the interpreter is a heavy weapon that should be only reserved for very tricky cases. In most cases, however, it's best avoided and simpler tools should be employed.
调用解释器的全部功能是一种重武器,应该只用于非常棘手的情况。然而,在大多数情况下,最好避免这样做,而应使用更简单的工具。
That said, like all generalizations, be wary of this one. In some cases, exec and eval can be valuable. But you must have a very good reason to use them. See this postfor one acceptable use.
也就是说,像所有的概括一样,要警惕这一点。在某些情况下, exec 和 eval 可能很有价值。但是你必须有一个很好的理由来使用它们。请参阅此帖子以了解一种可接受的用途。
回答by zzzeek
In contrast to what most answers are saying here, exec is actually part of the recipe for building super-complete decorators in Python, as you can duplicate everything about the decorated function exactly, producing the same signature for the purposes of documentation and such. It's key to the functionality of the widely used decorator module (http://pypi.python.org/pypi/decorator/). Other cases where exec/eval are essential is when constructing any kind of "interpreted Python" type of application, such as a Python-parsed template language (like Mako or Jinja).
与大多数答案在这里所说的相反,exec 实际上是在 Python 中构建超级完整装饰器的秘诀的一部分,因为您可以完全复制有关装饰函数的所有内容,为文档等目的生成相同的签名。它是广泛使用的装饰器模块 ( http://pypi.python.org/pypi/decorator/)功能的关键。其他 exec/eval 必不可少的情况是在构建任何类型的“解释型 Python”类型的应用程序时,例如 Python 解析的模板语言(如 Mako 或 Jinja)。
So it's not like the presence of these functions are an immediate sign of an "insecure" application or library. Using them in the naive javascripty way to evaluate incoming JSON or something, yes that's very insecure. But as always, its all in the way you use it and these are very essential functions.
因此,这些函数的存在并不是“不安全”应用程序或库的直接标志。以天真的 javascripty 方式使用它们来评估传入的 JSON 或其他东西,是的,这非常不安全。但与往常一样,一切都取决于您使用它的方式,这些都是非常重要的功能。
回答by jathanism
I have used eval()
in the past (and still do from time-to-time) for massaging data during quick and dirty operations. It is part of the toolkit that can be used for getting a job done, but should NEVER be used for anything you plan to use in productionsuch as any command-line tools or scripts, because of all the reasons mentioned in the other answers.
我eval()
过去曾使用过(并且仍然不时使用)在快速和肮脏的操作期间按摩数据。它是工具包的一部分,可用于完成工作,但绝不应用于您计划在生产中使用的任何东西,例如任何命令行工具或脚本,因为其他答案中提到的所有原因。
You cannot trust your users--ever--to do the right thing. In most cases they will, but you have to expect them to do all of the things you never thought of and find all of the bugs you never expected. This is precisely where eval()
goes from being a tool to a liability.
你不能相信你的用户——永远——做正确的事情。在大多数情况下,他们会,但您必须期望他们完成您从未想过的所有事情并找到您从未想过的所有错误。这正是eval()
从工具变成责任的地方。
A perfect example of this would be using Django, when constructing a QuerySet
. The parameters passed to a query accepts keyword arguments, that look something like this:
一个完美的例子是在构建QuerySet
. 传递给查询的参数接受关键字参数,如下所示:
results = Foo.objects.filter(whatever__contains='pizza')
If you're programmatically assigning arguments, you might think to do something like this:
如果您以编程方式分配参数,您可能会想这样做:
results = eval("Foo.objects.filter(%s__%s=%s)" % (field, matcher, value))
But there is always a better way that doesn't use eval()
, which is passing a dictionary by reference:
但总有一种更好的方法不使用eval()
,即通过引用传递字典:
results = Foo.objects.filter( **{'%s__%s' % (field, matcher): value} )
By doing it this way, it's not only faster performance-wise, but also safer and more Pythonic.
通过这样做,它不仅在性能方面更快,而且更安全和更 Pythonic。
Moral of the story?
这个故事所讲的道德?
Use of eval()
is okfor small tasks, tests, and truly temporary things, but badfor permanent usage because there is almost certainly always a better way to do it!
使用eval()
是OK的小任务,测试,真正临时的事情,但糟糕的永久使用,因为那里几乎可以肯定总有更好的方式来做到这一点!
回答by dmckee --- ex-moderator kitten
Allowing these function in a context where they might run user input is a security issue, and sanitizers that actually work are hard to write.
在可能运行用户输入的上下文中允许这些函数是一个安全问题,并且很难编写实际工作的消毒剂。
回答by Azeem.Butt
Same reason you shouldn't login as root: it's too easy to shoot yourself in the foot.
您不应该以 root 身份登录的原因相同:用脚射击自己太容易了。
回答by Chris
s = "import shutil; shutil.rmtree('/nonexisting')"
eval(s)
Now assume somebody can control s from a web application, for example.
例如,现在假设有人可以从 Web 应用程序控制 s。
Don't try to do this on your computer
不要尝试在您的计算机上执行此操作
回答by Rushyo
Reason #1: One security flaw (ie. programming errors... and we can't claim those can be avoided) and you've just given the user access to the shell of the server.
原因#1:一个安全漏洞(即编程错误......我们不能声称这些是可以避免的)并且您刚刚授予用户访问服务器外壳的权限。