如何保护Python类变量不被恶意程序员访问?
我该如何保护我的变量,避免受到这种攻击呢:
MyClass.__dict__ = {}
MyClass.__dict__.__setitem__('_MyClass__protectedVariable','...but it is not')
上面的代码会改变变量的字典,之后就很容易修改所有的变量。最上面那行代码是实现这一切的关键。如果你的字典的 __setitem__
方法像下面这样被修改了,上面的做法就不管用了。
我想强制用户使用我的方法 setProtectedVariable(value)
来修改变量,但在 Python 2.7 中似乎找不到办法。有没有什么想法?
如果你能发现下面代码中的其他类似漏洞,我也会很感激(我注意到我应该在 myDict.__setitem__
的 inspect.stack
检查中添加文件名和行号)。
这是我到目前为止尝试过的:
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()
4 个回答
据我所知,Python里其实没有什么好的办法来做到这一点。无论你怎么做,别人总是可以复制你的代码,然后去掉你设置的保护,或者(在大多数情况下)直接从这个类继承并重写它,或者直接重新赋值方法。
不过:你为什么这么在意呢?如果你把它命名为__whatever
,这就很清楚地说明了,如果用户去碰这个东西,发生任何不好的事情都是他们自己的错。
在Python中,你不能通过这种方式来“保护”属性。你和调用你代码的人之间为什么要有对立关系呢?你们需要在一些事情上达成一致,这就是其中之一。写好文档,和他建立更好的关系。其实我不知道你真正的问题是什么,但这不是代码能解决的。
其他语言,比如Java和C++,提供了像private
这样的功能来进行分离,但Python就是没有这种机制。你不能事后再加上去。
如果你能多告诉我们一些关于这个“坏程序员”的事情,以及你们为什么在代码使用上有分歧,我们也许能给你一些其他的解决思路。
我觉得这个问题背后有一些深层的困惑。私有变量并不是为了防止那些“坏黑客”的攻击,它们和安全性没有关系。私有变量的存在是为了促进良好的编程习惯,比如保持低耦合度。
如果一个“坏程序员”能访问你的源代码,他或她可以随意修改它。把一个变量标记为“私有”并不能改变这一点。如果这个坏程序员想要破坏你在其他系统上运行的程序……把变量叫做“私有”也没有任何帮助。这并不会改变程序在内存中存储和操作的方式。它只是以一种我认为不必要复杂的方式,强制执行了关注点分离。
另外,值得注意的是,在正常情况下,你并不需要经历这些复杂的操作……
MyClass.__dict__ = {}
MyClass.__dict__.__setitem__('_MyClass__protectedVariable','...but it is not')
……就可以给一个受保护的变量赋值。你甚至不需要重写 __dict__
。你只需要这样做:
MyClass._MyClass__protectedVariable = '...but it is not'
因为它真的不是那么复杂。受保护的变量,我是说。名字混淆的主要目的是为了防止命名空间冲突。如果你只是想要一个“私有”的属性,只需在前面加一个下划线。希望你的用户能遵循这个约定,但也要做好准备,任何不守规矩的人都会不管你怎么做而破坏它。