E 'possibile costruire un valore restituito da eval
che getterebbe una un'eccezionefuorieval
se si è tentato di print
, log
, repr
, qualsiasi cosa:
eval('''((lambda f: (lambda x: x(x))(lambda y: f(lambda *args: y(y)(*args))))
(lambda f: lambda n: (1,(1,(1,(1,f(n-1))))) if n else 1)(300))''')
Questo crea una tupla nidificato di modulo (1,(1,(1,(1...
; tale valore non può essere print
ed (su Python 3), str
edo repr
ed; tutti i tentativi di eseguire il debug porterebbe a
RuntimeError: maximum recursion depth exceeded while getting the repr of a tuple
pprint
e saferepr
non troppo:
...
File "/usr/lib/python3.4/pprint.py", line 390, in _safe_repr
orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level)
File "/usr/lib/python3.4/pprint.py", line 340, in _safe_repr
if issubclass(typ, dict) and r is dict.__repr__:
RuntimeError: maximum recursion depth exceeded while calling a Python object
Quindi non v'è alcuna funzione di sicurezza integrata per stringa i questo: le seguenti aiuto potrebbe essere utile:
def excsafe_repr(obj):
try:
return repr(obj)
except:
return object.__repr__(obj).replace('>', ' [exception raised]>')
E poi c'è il problema che print
in Python in realtà non utilizza str
/repr
, quindi non si ha alcuna sicurezza a causa della mancanza di controlli di ricorsione.Cioè, prendi il valore di ritorno del mostro lambda sopra, e non puoi str
, repr
, ma il numero ordinario print
(non print_function
!) Lo stampa bene. Tuttavia, è possibile sfruttare questo per generare un SIGSEGV su Python 2 se si sa che verrà stampato utilizzando l'istruzione print
:
print eval('(lambda i: [i for i in ((i, 1) for j in range(1000000))][-1])(1)')
crash Python 2 con SIGSEGV. This is WONTFIX in the bug tracker. Quindi non usare mai print
-la dichiarazione se vuoi essere sicuro. from __future__ import print_function
!
Questa non è una dura, ma
eval('(1,' * 100 + ')' * 100)
quando viene eseguito, uscite
s_push: parser stack overflow
Traceback (most recent call last):
File "yyy.py", line 1, in <module>
eval('(1,' * 100 + ')' * 100)
MemoryError
Il MemoryError
possono essere catturati, è una sottoclasse di Exception
. Il parser ha qualche really conservative limits to avoid crashes from stackoverflows (gioco di parole). Tuttavia, s_push: parser stack overflow
viene emesso a stderr
dal codice C e non può essere soppresso.
E proprio ieri ho chiesto why doesn't Python 3.4 be fixed for a crash from,
% python3
Python 3.4.3 (default, Mar 26 2015, 22:03:40)
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class A:
... def f(self):
... nonlocal __x
...
[4] 19173 segmentation fault (core dumped) python3
e Serhiy Storchaka's answer confermato che gli sviluppatori di base Python non considerano SIGSEGV sul codice apparentemente ben formato un problema di sicurezza:
solo la sicurezza le correzioni sono accettate per 3.4.
Quindi si può concludere che non può mai essere considerato sicuro eseguire qualsiasi codice da terze parti in Python, disinfettato o meno.
E Nick Coghlan poi added:
E come alcuni retroscena aggiuntive sul motivo per cui gli errori di segmentazione provocate dal codice Python non sono attualmente considerati un bug di sicurezza: dal CPython non include una sandbox di sicurezza, noi' stiamo già facendo affidamento interamente sul sistema operativo per fornire l'isolamento del processo. Questo limite di sicurezza a livello di sistema operativo non è influenzato dal fatto che il codice sia in esecuzione "normalmente" o in uno stato modificato in seguito a un errore di segmentazione deliberatamente attivato.
Questo dipende da cosa intendi per pericoloso ... Immagino che un utente malintenzionato potrebbe creare un'espressione per fare un _really_ grande numero intero che li induca a corto di memoria .... – mgilson
@mgilson che è un punto valido Suppongo che sia possibile proteggersi da questo mettendo protezioni di memoria/tempo sulla vostra applicazione, ma sicuramente ne vale la pena essere a conoscenza. – asmeurer
Penso che questo dipenda anche dalla gente del posto che passi in ... 'a + b' è sicuro solo come' a .__ add__' e 'b .__ radd__' sono sicuri ... – mgilson