How can I protect my variables from this kind of attack:
MyClass.__dict__ = {}
MyClass.__dict__.__setitem__('_MyClass__protectedVariable','...but it is not')
The above changes the variable dictionary and after that it is childs play to change all the variables. The upper line is crucial for this to work. The above does not work if your dictionary’s __setitem__ is tweaked like below).
I want to force user to use my method setProtectedVariable(value) to change the variable, but I seem to find no way of doing that in Python 2.7. Any ideas?
I appreciate also if you find other similar holes from the code below (I noticed that I should add also the file name and line number to my inspect.stack check in myDict.__setitem__).
This is what I have tried so far:
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()
I feel that there is some deep confusion motivating this question. Private variables aren’t there to keep the evil “hackers” away. They have nothing to do with security. They’re there to promote good programming practices like maintaining low coupling.
If an “evil programmer” has access to your source code, he or she can do whatever he or she wants to with it. Calling a variable “private” won’t change that. If said evil programmer is trying to compromise your program executing on another system… calling a variable “private” will do you no good. It doesn’t change anything about the way the program is stored and manipulated in memory. It just enforces (in an unnecessarily complex way IMO) separation of concerns.
Also, it’s worth noting that under normal circumstances you don’t have to go through all these shenanigans…
…to assign to a protected var. You don’t even have to overwrite
__dict__. You can just do this:Cause it’s really not. Protected, I mean. The main purpose of name mangling is to prevent namespace collisions. If you just want a “private” attribute, simply prefix it with a single underscore. Expect your users to respect convention, and expect your abusers to break it no matter what you do.