Why should exec() and eval() be av

2018-12-31 06:42发布

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()?

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?

标签: python
11条回答
若你有天会懂
2楼-- · 2018-12-31 07:02

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.

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.

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.

查看更多
无与为乐者.
3楼-- · 2018-12-31 07:07

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.

查看更多
临风纵饮
4楼-- · 2018-12-31 07:07

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.

查看更多
春风洒进眼中
5楼-- · 2018-12-31 07:10

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.

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 post for one acceptable use.

查看更多
余生无你
6楼-- · 2018-12-31 07:10

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 production such as any command-line tools or scripts, because of all the reasons mentioned in the other answers.

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.

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:

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:

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.

Moral of the story?

Use of eval() is ok for small tasks, tests, and truly temporary things, but bad for permanent usage because there is almost certainly always a better way to do it!

查看更多
妖精总统
7楼-- · 2018-12-31 07:10
s = "import shutil; shutil.rmtree('/nonexisting')"
eval(s)

Now assume somebody can control s from a web application, for example.

Don't try to do this on your computer

查看更多
登录 后发表回答