用于列表反序列化的Python'eval'的安全性

时间:2009-07-11 01:25:20

标签: python eval

此方案中是否存在任何安全漏洞:

eval(repr(unsanitized_user_input), {"__builtins__": None}, {"True":True, "False":False})

其中unsanitized_user_input是str对象。字符串是用户生成的,可能很讨厌。假设我们的Web框架没有让我们失望,那么它就是来自Python内置函数的一个真正的诚实的str实例。

如果这很危险,我们可以对输入做任何事情以使其安全吗?

我们肯定想要执行字符串中包含的任何内容。

另见:

(我认为)对这个问题不重要的更大背景是我们有成千上万的这些:

repr([unsanitized_user_input_1,
      unsanitized_user_input_2,
      unsanitized_user_input_3,
      unsanitized_user_input_4,
      ...])

在某些情况下嵌套:

repr([[unsanitized_user_input_1,
       unsanitized_user_input_2],
      [unsanitized_user_input_3,
       unsanitized_user_input_4],
       ...])

它们本身转换为repr()的字符串,放入持久存储器,最后用eval读回内存。

Eval从持久存储中反序列化字符串比pickle和simplejson快得多。解释器是Python 2.5所以json和ast不可用。不允许使用C模块,不允许使用cPickle。

5 个答案:

答案 0 :(得分:19)

确实很危险,最安全的选择是ast.literal_eval(请参阅标准库中的ast模块)。您当然可以构建和更改ast以提供例如eval。在评估结果AST之前评估变量等(当它归结为文字时)。

True的可能利用从它可以得到的任何对象开始(比如说object)并通过.__ class_进入其类型对象等,直至eval ,然后得到它的子类...基本上它可以到达任何对象类型和破坏破坏。我可以更具体,但我宁愿不在公共论坛中这样做(漏洞利用是众所周知的,但考虑到有多少人仍然忽略它,揭示它想要脚本小子可能会让事情变得更糟......只是避免{{ 1}}关于未经授权的用户输入并且从此过上幸福的生活! - )。

答案 1 :(得分:8)

如果您可以毫无疑问地证明unsanitized_user_input是来自Python内置函数的str实例而没有被篡改,那么这总是安全的。实际上,即使没有所有这些字符串对象eval(repr(astr)) = astr以外的所有额外参数,它也是安全的。你输入一个字符串,你得到一个字符串。你所做的一切都是逃避和不受欢迎。

这一切都让我觉得eval(repr(x))不是你想要的 - 除非有人给你一个看起来像字符串但不是的unsanitized_user_input对象,否则不会执行任何代码,但这是一个不同的问题 - 除非你试图以最慢的方式复制字符串实例:D。

答案 2 :(得分:4)

根据你所描述的一切,在eval repred字符串的技术上是安全的,但是,我总是避免这样做,因为它要求麻烦:

  • 可能存在一些奇怪的角落情况,你的假设只存储了重新编写的字符串(例如,一个错误/不同的路径进入存储器,不会立即重新编写因为代码注入利用,否则它可能会不可利用)

  • 即使现在一切正常,假设可能会在某些时候发生变化,未知数据可能会被不知道eval代码的人存储在该字段中。

  • 您的代码可能会被重复使用(或更糟糕的是,复制+粘贴)到您未考虑的情况中。

正如Alex Martelli指出的那样,在python2.6及更高版本中,有ast.literal_eval可以安全地处理字符串和其他简单的数据类型,如元组。这可能是最安全,最完整的解决方案。

然而,另一种可能性是使用string-escape编解码器。这比eval快得多(根据timeit大约10倍),在早期版本中比literal_eval更快,并且应该做你想做的事情:

>>> s = 'he\nllo\' wo"rld\0\x03\r\n\tabc'
>>> repr(s)[1:-1].decode('string-escape') == s
True

([1:-1]是去除外部引号repr添加。)

答案 3 :(得分:3)

通常,您绝不允许任何人发布代码。

所谓的“付费专业程序员”有足够的时间编写实际可行的代码。

接受来自匿名公众的代码 - 没有正式质量保证的好处 - 是所有可能情况中最糟糕的。

专业程序员 - 没有良好,可靠的正式QA - 几乎可以对任何网站进行哈希处理。实际上,我正在从付费专业人员那里逆向设计一些令人难以置信的糟糕代码。

允许非专业人士 - 不受QA限制 - 发布代码的想法真的很可怕。

答案 4 :(得分:1)

repr([unsanitized_user_input_1,
      unsanitized_user_input_2,
      ...
     

... unsanitized_user_inputstr对象

您不必序列化字符串以将其存储在数据库中。

如果这些都是字符串,正如您所提到的那样 - 为什么不能将字符串存储在db.StringListProperty

嵌套条目可能有点复杂,但为什么会这样呢?当你不得不求助于eval从数据库中获取数据时,你可能做错了什么..

你不能将每个unsanitized_user_input_x存储为自己的db.StringProperty行,并将它们按参考字段分组吗?

其中任何一个都可能不适用,因为我不知道你想要实现什么,但我的观点是 - 你能否以一种你不必依赖的方式构建数据{{{ 1}}(并且还依赖它不是安全问题)?

相关问题