2009-07-11 69 views
6

都是有可能發生在這種情況下,任何安全漏洞:安全Python中的eval「列表反序列化

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

其中unsanitized_user_input是海峽對象。該字符串是用戶生成的,可能是令人討厭的。假設我們的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。

+0

「如果我提出更大的背景,這樣做的理由會更有意義。」您能否詳細說明問題?目前這個命令看起來完全沒有意義 - 與「unsanitized_user_input」無關。 – dbr 2009-07-11 02:13:49

+0

「我們有成千上萬個」這沒有任何意義。你爲什麼要以這種方式存儲輸入? repr()用於存儲目的沒有意義。 – Miles 2009-07-11 04:58:42

+0

你爲什麼不使用泡菜或更簡單的東西? – 2009-07-11 11:11:10

回答

19

確實很危險,最安全的選擇是ast.literal_eval(參見標準庫中的ast模塊)。您當然可以製作並更改ast以提供例如評估變量等之前,你評估產生的AST(當它下降到文字)。

可能利用的eval開始與任何對象就可以得到它的手(比如說True這裏),並通過.__ class_將其類型的對象,等等,直到object,然後獲取它的子類...基本上它可以得到任何對象類型並破壞浩劫。我可以更具體一些,但我寧願不在公共論壇上這樣做(該漏洞衆所周知,但考慮到有多少人仍然忽略它,揭示它想要編寫腳本小子可能會讓事情變得更糟......只是爲了避免eval無用的用戶輸入並從此過上快樂的生活! - )。

3

通常,您絕不應允許任何人發佈代碼。

所謂的「付費專業程序員」有足夠的時間編寫實際可行的代碼。

接受來自匿名公衆的代碼 - 沒有正式QA的好處 - 是所有可能情況中最糟糕的情況。

專業程序員 - 沒有良好的,堅實的形式化QA--幾乎可以製作任何網站的散列。事實上,我正在從付費專業人員那裏逆向設計一些令人難以置信的糟糕代碼。

允許非專業的想法 - 通過QA支配 - 張貼代碼是真正可怕的。

8

如果您可以毫無疑問地證明unsanitized_user_input是Python內建的str實例,並且沒有任何篡改,那麼這總是安全的。事實上,它甚至會沒有因爲eval(repr(astr)) = astr所有這類字符串對象所有這些額外的參數是安全的。你放入一個字符串,你會返回一個字符串。你所做的只是逃避和逃避它。

這一切都讓我覺得eval(repr(x))是不是你想要的 - 除非有人給你一個unsanitized_user_input對象,看起來像一個字符串,但也不是沒有代碼永遠不會被執行,但是這是一個不同的question--除非您嘗試以儘可能最慢的方式複製字符串實例:D。

4

有了一切,你的描述,它在技術上是安全的EVAL repred琴絃,不過,我會避免反正這樣做,因爲它是自找麻煩:

  • 可能有一些奇怪的角落情況下你假設只有被重新存儲的字符串被存儲(例如,一個錯誤/到存儲中的不同路徑,不立即重新編寫代碼注入漏洞,否則它可能是不可開發的)

  • 即使現在一切正常,假設可能會在某些時候發生變化,並且unsanitised的數據可能會被某人的una存儲在該字段中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]是剝離外部報價再版補充道。)

1
repr([unsanitized_user_input_1, 
     unsanitized_user_input_2, 
     ... 

... unsanitized_user_inputstr對象

你不應該序列化的字符串將它們存儲在一個大tabase ..

如果這些都是字符串,如你所提到的 - 爲什麼你就不能字符串存儲在db.StringListProperty

嵌套條目可能會更復雜一些,但爲什麼是這樣的話?當你不得不求助於從數據庫中獲取數據時,你可能做錯了什麼。

難道你不能存儲每個unsanitized_user_input_x作爲它自己的db.StringProperty行,並通過引用字段將它們分組嗎?

這兩者中的任何一個都可能不適用,因爲我不知道你想達到什麼目的,但我的觀點是 - 你能不能以不依賴於eval的方式構造數據(並且依靠它不是一個安全問題)?