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

gra*_*ion 6 python eval

在这种情况下是否存在任何可能发生的安全漏洞:

eval(repr(unsanitized_user_input), {"__builtins__": None}, {"True":True, "False":False})
Run Code Online (Sandbox Code Playgroud)

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

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

我们当然希望执行字符串中包含的任何东西.

也可以看看:

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

repr([unsanitized_user_input_1,
      unsanitized_user_input_2,
      unsanitized_user_input_3,
      unsanitized_user_input_4,
      ...])
Run Code Online (Sandbox Code Playgroud)

在某些情况下嵌套:

repr([[unsanitized_user_input_1,
       unsanitized_user_input_2],
      [unsanitized_user_input_3,
       unsanitized_user_input_4],
       ...])
Run Code Online (Sandbox Code Playgroud)

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

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

Ale*_*lli 19

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

可能利用eval任何对象开始它可以得到它的手(比如True这里)并通过.__ class_到它的类型对象等等object,然后得到它的子类......基本上它可以到达任何对象类型和残骸破坏.我可以更具体,但我宁愿不在公共论坛上做这个(漏洞利用是众所周知的,但考虑到有多少人仍然忽视它,揭示它想要脚本小子可能会让事情变得更糟......只是避免eval在未经过用户输入和幸福生活! - ).


hao*_*hao 8

如果你可以毫无疑问地证明这unsanitized_user_inputstrPython内置函数中没有被篡改的实例,那么这总是安全的.事实上,即使没有所有这些额外的参数,它也是安全的,因为eval(repr(astr)) = astr对于所有这样的字符串对象.你输入一个字符串,你得到一个字符串.你所做的一切都是逃避并且不受欢迎.

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


Bri*_*ian 5

对于您描述的所有内容,评估 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
Run Code Online (Sandbox Code Playgroud)

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