2012-02-07 39 views
5

如何保護我的變量免受此類攻擊:以上如何從邪惡的程序員保護python類變量?

MyClass.__dict__ = {} 
MyClass.__dict__.__setitem__('_MyClass__protectedVariable','...but it is not') 

改變可變字典之後,它是孩子的​​發揮改變所有的變量。上限對於這項工作至關重要。如果你的字典的__setitem__像下面那樣調整過,以上不起作用)。

我想強制用戶使用我的方法setProtectedVariable(value)來更改變量,但我似乎在Python 2.7中找不到這樣做的方法。有任何想法嗎?

我也很欣賞,如果你從下面的代碼中找到其他類似的漏洞(我注意到我應該添加文件名和行號到我的inspect.stack檢查myDict.__setitem__)。

這是我到目前爲止已經試過:

import inspect 

class ProtectionTest: 

    __myPrivate = 0 

    def __init__(self): 
     md = myDict() 
     setattr(self,'__dict__', md) 

    def __setattr__(self, name, val):  
     if name == '__myPrivate': 
      print "failed setattr attempt: __myPrivate" 
      pass 
     elif name == '_ProtectionTest__myPrivate': 
      print "failed setattr attempt: _ProtectionTest__myPrivate" 
      pass 
     elif name == '__dict__': 
      print "failed setattr attempt: __dict__" 
      pass 
     else: 
      self.__dict__[name] = val    

    def getMyPrivate(self): 
     return self.__myPrivate 

    def setMyPrivate(self, myPrivate): 
     #self.__dict__['_ProtectionTest__stack'] = inspect.stack()[0][1:] 
     self.__dict__['_ProtectionTest__myPrivate'] = -myPrivate 

class myDict(dict): 

    def __init__(self): 
     dict.__init__(self) 

    def __setitem__(self, key, value): 
     if inspect.stack()[1][3] == 'setMyPrivate': 
      dict.__setitem__(self,key,value) 
     else: 
      print "failed dict attempt" 
      pass 

pt = ProtectionTest() 

print "trying to change... (success: 1): " 
pt.__myPrivate = 1 
print pt.getMyPrivate(), '\n' 

print "trying to change... (success: 2): " 
pt._ProtectionTest__myPrivate = 2 
print pt.getMyPrivate() , '\n' 

print "trying to change... (success: 3): " 
pt.__dict__['_ProtectionTest__myPrivate'] = 3 
print pt.getMyPrivate() , '\n' 

print "trying to change the function (success: 4): " 
def setMyPrivate(self, myPrivate): 
    self.__dict__['_ProtectionTest__myPrivate'] = 4 
pt.setMyPrivate = setMyPrivate 
pt.setMyPrivate(0) 
print pt.getMyPrivate(), '\n' 

print "trying to change the dict (success: 5): " 
pt.__dict__ = {} 
pt.__dict__.__setitem__('_ProtectionTest__myPrivate',5) 
print pt.getMyPrivate(), '\n' 

print "Still working (correct output = -input = -100): "  
pt.setMyPrivate(100) 
print pt.getMyPrivate() 
+5

你爲什麼要這麼做?你爲什麼關心另一個程序員在你的課堂上做什麼?如果另一位程序員想濫用這個問題,你負責讓你的代碼按照規範正常工作,不是嗎? – 2012-02-07 15:47:06

+0

我懷疑你會發現一個防彈的方法來防止惡意用戶的任何可能的濫用。你現在不妨放棄。 – NPE 2012-02-07 15:47:47

+1

你今天很積極......這也是對這個問題的回答:是否存在python中的私有變量和方法以及它們爲什麼存在。 – Juha 2012-02-07 15:52:54

回答

18

我覺得存在一些激發這個問題的深層困惑。私有變量不能保持邪惡的「黑客」。他們與安全無關。他們在那裏促進良好的編程實踐,如maintaining low coupling

如果一個「邪惡的程序員」可以訪問你的源代碼,他或她可以做任何他或她想要的東西。調用變量「private」不會改變這一點。如果說這個邪惡的程序員試圖破壞你在另一個系統上執行的程序......調用一個變量「private」會對你沒有好處。它不會改變程序在內存中存儲和操作的方式。它只是執行(以不必要的複雜方式IMO)separation of concerns

此外,值得注意的是,在正常情況下,你不必去通過所有這些把戲......

MyClass.__dict__ = {} 
MyClass.__dict__.__setitem__('_MyClass__protectedVariable','...but it is not') 

...分配給一個受保護的變種。你甚至不需要覆蓋__dict__。你可以這樣做:

MyClass._MyClass__protectedVariable = '...but it is not' 

因爲這是真的。受保護的,我的意思是。名稱修改的主要目的是防止namespace collisions。如果你只想要一個「私人」屬性,只需要用一個下劃線作爲前綴。期望您的用戶遵守慣例,並期望無論您做什麼,您的濫用者都會破壞它。

+0

在我研究你的答案時,我注意到你提到的兩個「shenanigans」有一個很大的區別:前者調用「object .__ dict __.__ setitem__',後者調用'object .__ setattr__'。這對整體結果沒有太大的影響,但我認爲如果你的系統稍微有些異常(比如在這種情況下),這是值得一提的。無論如何,很好的答案,謝謝。 – Juha 2012-02-08 12:26:51

+0

@Juha,好的,我明白你的意思了 - 我不清楚你是在討論你的custom_ __setattr__這種「攻擊」。我改變了上述以符合這種理解。 – senderle 2012-02-08 14:07:22

7

AFAIK有沒有真正的方式在Python做到這一點。無論你做什麼,任何人都可以隨時複製你的源代碼並刪除你的黑客,或者(大多數情況下)或者從類繼承並覆蓋它,或者直接重新分配方法。

但是:你爲什麼這麼在意?如果你把它命名爲__whatever這是非常明確的文件,如果用戶混淆這一點,發生的任何不良事件都是他們自己該死的錯。

8

在Python中,你不能用這種方法「保護」屬性。你爲什麼與你的來電者形成對抗關係?你和他需要同意一些事情,這是其中之一。寫出更好的文檔,與他成爲更好的朋友。我不知道你真正的問題是什麼,但它不能用代碼解決。

其他語言如Java和C++提供了與private等的分離,但是Python根本就沒有。在事實發生後你無法將其鎖定。

如果您告訴我們更多關於這個邪惡程序員是誰,以及您和他爲什麼不同意應該如何使用您的代碼,我們可能會爲您提供解決方案的其他建議。

+6

至少在C++中,甚至可以通過一些不是非常依賴平臺的方式繞過'private' :) – 2012-02-07 15:58:11

3

對於這種數據變更,Python不是很有保護性。但是這被看作是一個特徵。在`final` keyword equivalent for variables in Python?可能關於常量/決賽的一個不同的問題有一些幫助。 要回答你的問題:可能沒有辦法保護數據不會在你的類中使用外部代碼運行在同一個可執行文件中。您很可能需要將數據存儲在單獨的進程中,並提供某種與外部進程交換數據的API。