2012-02-07 9 views
5

Come posso proteggere i miei variabili da questo tipo di attacco:Come proteggere le variabili di classe Python da un programmatore malvagio?

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

È possibile che questo cambia il dizionario variabile e dopo che è un gioco da ragazzi per cambiare tutte le variabili. La linea superiore è cruciale per questo lavoro. Quanto sopra non funziona se il tuo dizionario è __setitem__ ottimizzato come di seguito).

Voglio forzare l'utente ad usare il mio metodo setProtectedVariable(value) per cambiare la variabile, ma non trovo il modo di farlo in Python 2.7. Qualche idea?

Apprezzo anche se trovi altri buchi simili dal codice qui sotto (ho notato che dovrei aggiungere anche il nome del file e il numero di linea al mio assegno inspect.stackmyDict.__setitem__).

Questo è quello che ho provato finora:

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

Perché vuoi farlo? Perché ti importa cosa fa un altro programmatore con la tua classe? Sei incaricato di far funzionare correttamente il tuo codice secondo le specifiche, se un altro programmatore vuole abusarne è il suo problema, vero? –

+0

Dubito che troverai un modo antiproiettile per proteggere da ogni possibile abuso da parte di un utente malintenzionato. Puoi anche arrenderti ora. – NPE

+1

Oggi sei positivo ... Questa è anche una risposta alla domanda: esistono variabili e metodi privati ​​in python e perché non esistono (esistono). – Juha

risposta

18

Sento che c'è una profonda confusione che motiva questa domanda. Le variabili private non sono lì per tenere lontani i malvagi "hacker". Non hanno nulla a che fare con la sicurezza. Sono lì per promuovere buone pratiche di programmazione come maintaining low coupling.

Se un "programmatore malvagio" ha accesso al codice sorgente, lui o lei può fare qualsiasi cosa lui o lei vuole con esso. Chiamare una variabile "privata" non lo cambierà. Se il programmatore malvagio sta cercando di compromettere il tuo programma in esecuzione su un altro sistema ... chiamare una variabile "privato" non ti farà bene. Non cambia nulla nel modo in cui il programma è memorizzato e manipolato in memoria. Applica semplicemente (in modo IMO inutilmente complesso) separation of concerns.

Inoltre, vale la pena notare che in circostanze normali non c'è bisogno di passare attraverso tutti questi imbrogli ...

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

... da assegnare a un var protetta. Non è nemmeno necessario sovrascrivere __dict__. Si può solo fare questo:

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

Causa è davvero no. Protetto, intendo. Lo scopo principale del mangling dei nomi è impedire namespace collisions. Se si desidera solo un attributo "privato", è sufficiente inserirlo con un trattino singolo. Aspettatevi che i vostri utenti rispettino le convenzioni e aspettatevi che i vostri abusatori si rompano, qualunque cosa voi facciate.

+0

Mentre stavo studiando la tua risposta ho notato che i due" imbrogli "che hai citato hanno una grossa differenza: l'ex chiama l'oggetto .__ dict __.__ setitem__' e quest'ultimo chiama 'oggetto .__ setattr__'. Questo non fa una grande differenza nel risultato complessivo, ma penso che sia degno di menzione se hai un sistema leggermente esotico (come in questo caso). Ad ogni modo, buona risposta, grazie. – Juha

+0

@Juha, OK, capisco cosa intendi: non mi era chiaro che stavi parlando di "questo tipo di attacco" sul tuo custom_ "__setattr__". Ho cambiato quanto sopra per comportarmi con quella comprensione. – senderle

7

per quanto ne so non c'è davvero un modo per fare questo in Python. Qualunque cosa tu faccia, chiunque potrebbe sempre copiare la tua fonte e rimuovere i tuoi hack, o (nella maggior parte dei casi) ereditare dalla classe e sovrascriverla o semplicemente riassegnare direttamente i metodi.

Ma: perché ti importa così tanto? Se la chiami, __whatever, è una documentazione molto chiara che se gli utenti si pasticciano, tutto ciò che accade male è colpa loro.

8

In Python, non è possibile "proteggere" gli attributi in questo modo. Perché sei in una relazione antagonistica con il tuo interlocutore? Tu e lui dovete concordare su alcune cose, questa è una di quelle. Scrivi documenti migliori, diventa migliore amico di lui. Non so quale sia il tuo vero problema, ma non può essere risolto con il codice.

Altri linguaggi come Java e C++ offrono separazione con private e così via, ma semplicemente Python no. Non puoi accenderlo dopo il fatto.

Se ci dite di più su chi sia questo malvagio programmatore e perché voi e lui non siete d'accordo su come il vostro codice dovrebbe essere usato, potremmo essere in grado di darvi altre idee per soluzioni.

+6

Almeno in C++ anche quel 'private' può essere aggirato in alcuni modi non terribilmente dipendenti dalla piattaforma :) –

3

Python non è molto protettivo per questo tipo di modifica dei dati. Ma questa è vista come una caratteristica. Forse una domanda diversa su costanti/finali a `final` keyword equivalent for variables in Python? è di qualche aiuto. Per rispondere alla tua domanda: Probabilmente non c'è modo di proteggere i dati dalla manipolazione della tua classe in esecuzione con codice estraneo nello stesso eseguibile. Probabilmente dovresti archiviare i tuoi dati in un processo separato e fornire una sorta di API per lo scambio di dati con il processo esterno.