Как защитить переменные класса Python от злого программиста? - PullRequest
5 голосов
/ 07 февраля 2012

Как я могу защитить свои переменные от такого рода атак:

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()  

Ответы [ 4 ]

18 голосов
/ 07 февраля 2012

Я чувствую, что есть некоторая глубокая путаница, мотивирующая этот вопрос. Частные переменные не предназначены для того, чтобы держать злых хакеров подальше. Они не имеют ничего общего с безопасностью. Они там, чтобы продвигать хорошие методы программирования, такие как поддержание низкой связи .

Если «злой программист» имеет доступ к вашему исходному коду, он или она может делать с ним все, что захочет. Вызов переменной «private» не изменит этого. Если злой программист пытается скомпрометировать вашу программу, выполняющуюся в другой системе ... вызов переменной "private" не принесет вам пользы. Это ничего не меняет в том, как программа хранится и управляется в памяти. Он просто обеспечивает (неоправданно сложный способ ИМО) разделение интересов .

Кроме того, стоит отметить, что в обычных условиях вам не нужно проходить через все эти махинации ...

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

... для назначения защищенной вар. Вам даже не нужно перезаписывать __dict__. Вы можете просто сделать это:

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

Потому что это действительно нет. Я имею в виду под защитой. Основная цель искажения имен - предотвратить столкновения пространства имен . Если вы просто хотите использовать атрибут private, просто поставьте перед ним один знак подчеркивания. Ожидайте, что ваши пользователи будут соблюдать соглашение, и ожидайте, что ваши нарушители нарушат его, независимо от того, что вы делаете.

8 голосов
/ 07 февраля 2012

В Python вы не можете «защитить» атрибуты таким образом. Почему у вас антагонистические отношения с вашим абонентом? Вам и ему нужно договориться о некоторых вещах, это одна из них. Напишите лучшие документы, станьте лучшими друзьями с ним. Я не знаю, какова ваша настоящая проблема, но она не может быть решена с помощью кода.

Другие языки, такие как Java и C ++, предлагают разделение с помощью private и т. Д., Но Python просто нет. Вы не можете запереть его после свершившегося факта.

Если вы расскажете нам больше о том, кто этот злой программист, и почему вы и он не согласны с тем, как следует использовать ваш код, мы могли бы дать вам другие идеи для решений.

7 голосов
/ 07 февраля 2012

AFAIK, на самом деле нет способа сделать это в Python. Независимо от того, что вы делаете, любой может всегда скопировать ваш исходный код и удалить ваши хаки, или (в большинстве случаев) либо наследовать от класса и переопределить его, либо просто напрямую переназначить методы.

Но: почему ты так заботишься? Если вы назовете это __whatever, это будет очень ясной документацией, что если пользователи возятся с этим, то все плохое, что происходит, является их собственной чертовой ошибкой.

3 голосов
/ 07 февраля 2012

Python не очень защищает от такого рода изменения данных.Но это считается особенностью.Может быть, другой вопрос о константах / финалах в `final` ключевом эквиваленте для переменных в Python? может помочь.Чтобы ответить на ваш вопрос: в вашем классе, вероятно, нет способа защитить данные от манипуляций, выполняемых с использованием чужого кода в том же исполняемом файле.Скорее всего, вам понадобится хранить ваши данные в отдельном процессе и предоставить какой-то API для обмена данными с внешним процессом.

...