¿Seguridad de eval() de Python en cadenas que no son de confianza?
Si estoy evaluando una cadena de Python usando eval() y tengo una clase como:
class Foo(object):
a = 3
def bar(self, x): return x + a
¿Cuáles son los riesgos de seguridad si no confío en la cadena? En particular:
- ¿ Es
eval(string, {"f": Foo()}, {})
inseguro? Es decir, ¿puede acceder al sistema operativo o al sistema o a algo que no sea seguro desde una instancia de Foo? - ¿ Es
eval(string, {}, {})
inseguro? Es decir, ¿puedo acceder al sistema operativo o al sistema completamente desde funciones integradas como len y list? - ¿Hay alguna manera de hacer que las funciones integradas no estén presentes en absoluto en el contexto de evaluación?
Hay algunas cadenas inseguras como "[0] * 100000000" que no me importan, porque en el peor de los casos ralentizan/detienen el programa. Lo que más me preocupa es proteger los datos del usuario externos al programa.
Obviamente, eval(string)
sin diccionarios personalizados no es seguro en la mayoría de los casos.
eval()
permitirá que datos maliciosos comprometan todo su sistema, maten a su gato, se coman a su perro y hagan el amor con su esposa.
Recientemente hubo un hilo sobre cómo hacer este tipo de cosas de forma segura en la lista de desarrolladores de Python y las conclusiones fueron:
- Es realmente difícil hacer esto correctamente.
- Requiere parches en el intérprete de Python para bloquear muchas clases de ataques.
- No lo hagas a menos que realmente quieras.
Comience aquí para leer sobre el desafío: http://tav.espians.com/a-challenge-to-break-python-security.html
¿En qué situación quieres usar eval()? ¿Quiere que un usuario pueda ejecutar expresiones arbitrarias? ¿O desea transferir datos de alguna manera? Quizás sea posible bloquear la entrada de alguna manera.
No se puede asegurar la evaluación con un enfoque de lista negra como este. Consulte Eval es realmente peligroso para ver ejemplos de entradas que segmentarán el intérprete CPython, darán acceso a cualquier clase que desee, etc.
Puede comenzar a os
utilizar funciones integradas: __import__('os')
.
Para Python 2.6+, el módulo ast puede ayudar; en particular ast.literal_eval
, aunque depende exactamente de lo que quieras evaluar.
Tenga en cuenta que incluso si pasa diccionarios vacíos a eval(), todavía es posible segmentar (C)Python con algunos trucos de sintaxis. Por ejemplo, pruebe esto en su intérprete:eval("()"*8**5)
Probablemente sea mejor darle la vuelta a la pregunta:
- ¿Qué tipo de expresiones quieres evaluar?
- ¿Puede asegurarse de que solo se evalúen () las cadenas que coincidan con alguna sintaxis estrictamente definida?
- Entonces considere si eso es seguro.
Por ejemplo, si desea permitir que el usuario ingrese una expresión algebraica para su evaluación, considere limitarla a nombres de variables de una letra, números y un conjunto específico de operadores y funciones. No eval() cadenas que contengan nada más.