2012-04-24 17 views
7

W dokumentacji Pythona stwierdza, że ​​pickle nie jest bezpieczny i nie powinien analizować niezaufanych danych wprowadzanych przez użytkownika. Jeśli to zbadacie; prawie wszystkie przykłady pokazują to za pomocą połączenia system() przez os.system.Zrozumienie niepewności Python Pickle

Nie jest dla mnie jasne, w jaki sposób os.system jest interpretowany poprawnie bez importowania modułu os.

>>> import pickle 
>>> pickle.loads("cos\nsystem\n(S'ls /'\ntR.") # This clearly works. 
bin boot cgroup dev etc home lib lib64 lost+found media mnt opt proc root run sbin selinux srv sys tmp usr var 
0 
>>> dir() # no os module 
['__builtins__', '__doc__', '__name__', '__package__', 'pickle'] 
>>> os.system('ls /') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
NameError: name 'os' is not defined 
>>> 

Czy ktoś może wyjaśnić?

Odpowiedz

9

Nazwa modułu (os) jest częścią kodu maszynowego, a pickle automatycznie importuje moduł:

# pickle.py 
def find_class(self, module, name): 
    # Subclasses may override this 
    __import__(module) 
    mod = sys.modules[module] 
    klass = getattr(mod, name) 
    return klass 

Uwaga linia __import__(module).

Funkcja jest wywoływana, gdy wykonywana jest instrukcja kodu bajtowego pikla trawnika GLOBAL 'os system'.

Ten mechanizm jest niezbędny do tego, aby można było odfiltrować wystąpienia klas, których moduły nie zostały jawnie zaimportowane do przestrzeni nazw wywołującego.

+1

+1 za znalezienie kodu modułu – tMC

2

Importowanie moduł tylko dodaje go do lokalnej przestrzeni nazw, co nie jest koniecznie jeden jesteś w wyjątkiem sytuacji, gdy tak nie jest.

>>> dir() 
['__builtins__', '__doc__', '__name__', '__package__'] 
>>> __import__('os') 
<module 'os' from '/usr/lib64/python2.7/os.pyc'> 
>>> dir() 
['__builtins__', '__doc__', '__name__', '__package__'] 
6

Jeśli używasz pickletools.dis rozbierać marynata można zobaczyć, jak to działa:

import pickletools 
print pickletools.dis("cos\nsystem\n(S'ls ~'\ntR.") 

wyjściowa:

0: c GLOBAL  'os system' 
11: ( MARK 
12: S  STRING  'ls ~' 
20: t  TUPLE  (MARK at 11) 
21: R REDUCE 
22: . STOP 

Pickle wykorzystuje prostą maszynę wirtualną opartą na stosie, która rejestruje instrukcje używane do rekonstrukcji obiektu. Innymi słowy marynowane instrukcje w swoim przykładzie to:

push self.find_class (module_name, class_name) tj naciskać os.system Push string 'ls ~' Budowa krotki z najwyższych pozycji stosu Zastosuj wpłacone do argtuple, zarówno na stosie. tj os.system (* ('ls ~',))

Source

+2

Tak, ale dlaczego nie wymaga "importowania os"? – NPE

+1

dir() próbuje dostarczyć interesujący zestaw nazw bardziej niż stara się dostarczyć ściśle lub konsekwentnie zdefiniowany zestaw nazw, a jego szczegółowe zachowanie może się zmieniać w różnych wersjach. Gdy importujesz moduł dynamicznie, nie ma gwarancji, że zobaczysz go z dir() –

8

Dla ogóle zbyt wiele informacji na temat pisania złośliwych Pickles, które wykraczają dużo dalej niż standardowy os.system() przykład zobaczyć presentation i towarzyszący mu paper.

+1

+1 za wykopanie bogatego zasobu – gauden

+0

niesamowite dzięki- – tMC