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()
In Python, there is no existence of “Private” instance variables that cannot be accessed except inside an object.
Python doesn't have real private variables, so use the __ prefix (two underlines at the beginning make a variable) from PEP 8. Use instance _class-name__private-attribute try to access private variables outside the class in Python.
In actual terms (practically), python doesn't have anything called private member variable in Python. However, adding two underlines(__) at the beginning makes a variable or a method private is the convention used by most python code.
Python's convention to make an instance variable protected is to add a prefix _ (single underscore) to it. This effectively prevents it from being accessed unless it is from within a sub-class.
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...
MyClass.__dict__ = {}
MyClass.__dict__.__setitem__('_MyClass__protectedVariable','...but it is not')
...to assign to a protected var. You don't even have to overwrite __dict__
. You can just do this:
MyClass._MyClass__protectedVariable = '...but it is not'
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With