Python的eval()函数在不可信的字符串上是否安全?

31
如果我使用 eval() 评估一个 Python 字符串,并且有一个类像这样:
class Foo(object):
    a = 3
    def bar(self, x): return x + a
如果我不信任一个字符串,会有哪些安全风险?特别是:
  1. eval(string, {"f": Foo()}, {}) 不安全吗?也就是说,可以从 Foo 实例中访问 os 或 sys 等不安全的内容吗?
  2. eval(string, {}, {}) 不安全吗?也就是说,可以完全通过内置函数(如 len 和 list)访问 os 或 sys 吗?
  3. 有没有一种方法可以使内置函数在 eval 上下文中根本不存在?
有一些像 "[0] * 100000000" 这样的不安全的字符串,我不关心,因为最坏的情况下它们会减慢/停止程序。我主要关心保护外部于程序之外的用户数据。
显然,在大多数情况下,没有自定义字典的 eval(string) 是不安全的。

如果在你执行 eval 的字符串中包含 import sys sys.dostuff,并且你不信任这些字符串,那么情况可能会变得非常糟糕。 - Vasil
eval具有很好的特性,它只允许表达式。因此,像=、import和print这样的东西是不被允许的。 - user79758
7
请尝试运行eval('__import__("sys").stdout.write("Hello Joe")') - John La Rooy
我主张用ast.literal_eval(strg)替换eval(strg) - perpetualstudent
6个回答

59

eval()将允许恶意数据危害您的整个系统,杀死您的猫,吃掉您的狗并与您的妻子做爱。

最近在python-dev列表中有一个关于如何安全地执行这种操作的线程,结论如下:

  • 这真的很难做到。
  • 需要对Python解释器进行补丁以阻止许多类攻击。
  • 除非你真的想这样做,否则不要这样做。

从这里开始阅读有关挑战的信息:http://tav.espians.com/a-challenge-to-break-python-security.html

您想在什么情况下使用 eval()? 您是否希望用户能够执行任意表达式? 还是您希望以某种方式传输数据? 可能可以以某种方式锁定输入。


9
@S. Lott — 安全的一个主要理念不是要预防坏事情发生吗?而不是之后希望你能够识别攻击者并说服他们不再做这样的事情吗?为什么要阻止好的做法呢? - Ben Blank
2
任何情况下,如果一个人在互联网上编写不受信任的代码并运行在您的系统上,就需要确保这些不受信任的人无法攻击您的系统。如果您使用eval()编写了不安全的代码,我会告诉您不应该那样做,这是我的责任。 - Jerub

21
你无法通过这样的黑名单方法来保护eval的安全性。请参见Eval really is dangerous,其中列举了一些输入示例,这些示例会导致CPython解释器崩溃、让您访问任何所需的类等等。

14

您可以使用内置函数来访问os__import__('os')

对于Python 2.6+,ast模块可能会有所帮助;特别是ast.literal_eval,不过这取决于您想要评估的内容。


是的,我主张用ast.literal_eval(strg)替换eval(strg) - perpetualstudent

7
请注意,即使您将空字典传递给eval(),仍然有可能通过一些语法技巧导致(C)Python崩溃。例如,在解释器上尝试执行以下代码:eval("()"*8**5)

哇,为什么会引起 segfault 呢? - jacob
2
它溢出了编译器的堆栈。 - Benjamin Peterson

4

你最好把问题转过来思考:

  1. 你想要评估什么样的表达式?
  2. 你能确保只有与某些严格定义的语法匹配的字符串被eval()吗?
  3. 然后考虑一下是否安全。

例如,如果你想让用户输入一个代数表达式进行评估,请考虑限制他们使用单字母变量名、数字和特定集合的运算符和函数。不要eval()包含其他任何内容的字符串。


3
如果他在写密码学程序,那么要么是Carol或Eve,如果是处理电子邮件,则是s.kiddie@aol.com,但我不知道我们是否已经确定了一般情况下是谁。 - MarkusQ
我会更进一步地问,你为什么要这样做呢? - Noufal Ibrahim
这是一个名为“28c3:不安全性科学”的好视频,描述了程序之间的接口。www.youtube.com/watch?v=3kEfedtQVOY它强烈鼓励输入消息要么是正则的,要么是上下文无关的。 - eric.frederich

2

Mark Pilgrim的Python深入教程中有一篇非常好的关于eval()不安全性的文章

引用自该文章:

最终,对于某些“安全”的定义,可以安全地评估不受信任的Python表达式,但在现实生活中,这种定义并不是非常有用。如果你只是玩玩,只传递可信输入,那么没问题。但其他任何事情都会带来麻烦。


1
链接已失效。 - GingerPlusPlus
@GingerPlusPlus:谢谢,看起来Mark把他的域名迁移了。我已经更新了链接。 - Tim Pietzcker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接