7

在这种情况下是否存在任何安全漏洞:

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

unsanitized_user_inputstr 对象在哪里。该字符串是用户生成的,可能很讨厌。假设我们的 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。

4

5 回答 5

19

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

可能的利用eval从它可以得到的任何对象开始(比如True这里)并通过 .__class_ 到它的类型对象等,直到object,然后得到它的子类......基本上它可以得到任何对象类型并破坏浩劫。我可以更具体一点,但我不想在公共论坛上这样做(这个漏洞是众所周知的,但考虑到有多少人仍然忽略它,将它透露给想要成为脚本小子的人可能会让事情变得更糟......只是避免eval在未经处理的情况下用户输入并从此过上幸福的生活!-)。

于 2009-07-11T01:33:02.293 回答
8

如果您可以毫无疑问地证明它unsanitized_user_inputstr来自 Python 内置函数的实例且没有被篡改,那么这始终是安全的。事实上,即使没有所有这些额外的参数,它也是安全的,因为eval(repr(astr)) = astr对于所有这样的字符串对象。你输入一个字符串,你得到一个字符串。你所做的只是逃避和逃避它。

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

于 2009-07-11T01:42:00.457 回答
5

正如您所描述的那样,从技术上讲,评估 repred 字符串是安全的,但是,无论如何我都会避免这样做,因为它会自找麻烦:

  • 可能存在一些奇怪的极端情况,您假设只存储了 repred 字符串(例如,进入存储的错误/不同路径不会立即 repr 成为代码注入漏洞,否则它可能无法被利用)

  • 即使现在一切正常,假设可能会在某个时候发生变化,未经处理的数据可能会被不知道 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 添加。)

于 2009-07-11T10:57:19.943 回答
3

一般来说,你不应该允许任何人发布代码。

所谓的“付费专业程序员”很难写出真正有效的代码。

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

专业的程序员——没有好的、可靠的正式质量保证——会为几乎任何网站制作散列。事实上,我正在对付费专业人士的一些令人难以置信的糟糕代码进行逆向工程。

允许非专业人士(不受 QA 阻碍)发布代码的想法确实令人恐惧。

于 2009-07-11T01:38:39.417 回答
1
repr([unsanitized_user_input_1,
      unsanitized_user_input_2,
      ...

...unsanitized_user_input是一个str对象

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

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

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

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

其中任何一个都可能不适用,因为我不知道您要实现什么,但我的意思是-您能否以您不必依赖的方式构造数据eval(并且也依赖这不是安全问题)?

于 2009-07-11T16:03:55.717 回答