关于"eval is evil"和"consenting adults"



我看到很多人说"eval是邪恶的/危险的/不安全的";,因为一个人可以做这样的事情:

eval("os.system('rm -rf /')")

而在其他帖子中,蟒蛇被认为是">同意的成年人";,您不必进行类型检查,因为python的风格是duck-typeing

那么下面的代码呢:

def foo(duck):
duck.quack()
class EvilDuck(object):
def quack(self):
os.system('rm -rf /')
foo(EvilDuck())

你通常如何避免这种情况?蟒蛇什么时候同意成年,什么时候不同意?

eval是邪恶的,因为用户输入会在某个时刻进入其中。你不必(好吧,不应该)担心代码假装没有删除所有文件,因为代码无论如何都可以做到这一点——tada:

def foo(duck):
duck.quack()
class EvilDuck(object):
os.system('rm -rf /')
def quack(self):
pass

rm -rf /也很有可能不起作用。)

基本上,"成年人同意"就是"相信你的代码"。eval是"信任所有代码"。根据代码的来源,eval可能很好,但99%的时间都是不必要的,而且也很难保证它的安全性。

对于Python来说,试图并监督用户阻止他们执行程序中的命令似乎很愚蠢,因为他们可以很容易地直接在shell命令行中键入命令,而根本不涉及Python。

鸭子打字是可以的,因为它不需要运行J.Random互联网用户编写的代码。您(大概)能够以与预期用途一致的方式调用您定义的对象。

eval()exec(也是Python 3中的一个函数,但是Python 2中的一个语句)在应用于未经充分验证的用户输入时被认为是危险的,因为如果没有验证,您将暴露于恶意用户群的意愿。

换句话说,像这样的代码

eval(raw_input("How may I hack you today? "))

正是因为用户可能选择进入

os.system("switch off your antivirus protection")

或者其他类似的风险。

顶级

在Python中使用eval是一种错误的做法吗?

答案给出了eval是糟糕的4个原因

  1. 几乎总是有更好的方法
  2. 非常危险且不安全
  3. 使调试变得困难
  4. 慢速

eval从安全角度来看尤其糟糕,如果字符串的任何部分是从用户输入中提取的,那么清除不受信任的用户输入/尝试保护eval通常毫无价值,但正如其他人所提到的,它远不是其类中唯一的错误。对来自pickle或json/yml/xml的不受信任/用户输入进行反序列化,包括反序列化任意对象,也存在类似的安全问题。

正如参数1/3/4所指出的,eval通常被认为是一个次优解决方案,即使除了安全问题之外,这些问题通常可以通过一点考虑来避免(通过不将其与用户输入生成的字符串一起使用)(尽管当它是一个很容易错过的实现细节时,这可能是一个问题)。

如果可能的话,使用其他python功能来实现同样的东西通常被认为是更好的代码/更可维护的。

尽管如此,std库中的namedtuple是使用~~eval~~exec(类似)实现的。

还有人提到了与goto的比较,后者在某些方面也"过于强大",但可能非常有用(但仅在c中)。

我已经用它为我的代码开发了有用的调试函数和类似ruby的字符串插值。

最新更新