2013-10-02 80 views
7

我有一個問題,我在選擇Python作爲一個可能的語言爲一個更大的項目的決定取決於答案 - 我不能拿出自己:Python對象封裝安全

我們都知道,Python有沒有real對象封裝,所以沒有什麼像對象的「私有」屬性。關於這個問題,Guido van Rossum說,人們可以在不被「允許」的情況下訪問外部物體的隱藏部分,「我們都是成年人」,「不這樣做」。 只要我寫的軟件掌握在我自己的手中,我就可以生活得很好,所以我對自己的錯誤負責,並且可以嘗試避免這樣的事情。

但是這裏來了我的問題: 如果我提供一個帶有一些插件的插件框架,它有一些擴展點,許多插件是由其他人提供的,也許是我不能完全信任的插件。

我該如何防止我的框架的內部構件被插件訪問?

有沒有辦法實現這一點,或者是唯一的方式來使用Python的信心,沒有人會濫用我的API?

+2

一些google搜索條件可以幫助你:[Sandbox python](http://www.google.com/search?q=sandboxed+python)。 –

+2

我真的不知道這是一個安全問題。誰被守了什麼? –

+2

我真的不得不承認,我有點不喜歡*「我們都知道Python沒有真正的對象封裝」的基調* :) –

回答

16

你應該從來沒有真正依靠privatepublic等安全(如「防範惡意代碼和外部的威脅」)。它們的意思是讓程序員避免在腳下自我射擊,而不是(電腦)安全措施。只要您繞過靜態編譯器檢查並直接進入內存,您還可以輕鬆訪問C++對象的私有成員字段,但是您會說C++缺乏真正的封裝嗎?

因此,您絕對不會真的使用privateprotected作爲針對C++和Java中的惡意插件的安全措施,並且我也假設C#。

最好的辦法是在單獨的進程中運行插件,並通過IPC/RPC甚至Web服務公開核心API,或者在sandbox(根據@MarkHildreth指出)運行它們。或者,您可以爲插件設置認證和簽名流程,以便您可以在潛在惡意插件分發之前進行查看和過濾。

注:

可以使用詞法閉包實際上實現真正的封裝:

def Foo(param): 
    param = [param] # because `nonlocal` was introduced only in 3.x 
    class _Foo(object): 
     @property 
     def param(self): 
      return param[0] 
     @param.setter 
     def param(self, val): 
      param[0] = val 
    return _Foo() 

foo = Foo('bar') 
print foo.param # bar 
foo.param = 'baz' 
print foo.param # baz 
# no way to access `foo._param` or anything 

......但即使這樣,該值實際上仍然是通過反射比較方便:

>>> foo.__class__.param.fget.__closure__[0].cell_contents[0] = 'hey' 
>>> foo.param 
'hey' 

...即使這是不可能的,我們還是會留下ctypes允許直接內存訪問,繞過任何剩餘的化妝品「限制」:

import ctypes 
arr = (ctypes.c_ubyte * 64).from_address(id(foo)) 

,現在你可以直接分配給arr或從它讀;儘管您必須努力從那裏遍歷指針,直到存儲.param的實際內存位置,但它證明了這一點。

+3

好吧。這個答案本身不僅非常有用,而且這些鏈接也非常有趣和有用。你將封裝看作是一種編程工具而不是安全措施,這是非常好的區別。 – Gray

+1

+1。我也傾向於感嘆Python缺乏真正的訪問控制,但僅僅是因爲它讓我很容易在自己的類中編寫糟糕的OOP。即使有第三方課程,學習公共API也是我通常傾向於投入的努力,但我不能說我有足夠的動力去捅入內部,以至於控制別人的內容班級會有明顯的差異。 –

+0

@ErikAllik非常感謝你 - 這是我正在尋找的答案。不知道在Java中可以訪問私有成員。在C++中,我認爲是這樣,但我仍然把它放入Voodoo抽屜裏... – nerdoc