¿Seguridad de eval () de Python en cadenas no confiables?

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:

  1. ¿Es eval(string, {"f": Foo()}, {}) inseguro? Es decir, ¿puede alcanzar os o sys o algo inseguro desde una instancia de Foo?
  2. Es eval(string, {}, {}) inseguro? Es decir, ¿puedo acceder a os o sys por completo desde builtins como len y list?
  3. ¿Hay una manera de hacer que los componentes no estén presentes en absoluto en el contexto de evaluación?

Hay algunas cadenas inseguras como “[0] * 100000000” No me importa, porque en el peor de los casos ralentizan / detienen el progtwig. Me preocupa principalmente proteger los datos de usuario externos al progtwig.

Obviamente, eval(string) sin diccionarios personalizados no es seguro en la mayoría de los casos.

No puede asegurar eval con un enfoque de lista negra como este. Ver Eval realmente es peligroso para los ejemplos de entrada que segregarán al intérprete de CPython, le darán acceso a cualquier clase que desee, y así sucesivamente.

eval() permitirá que los datos maliciosos comprometan todo tu sistema, maten a tu gato, se coman a tu perro y hagan el amor con tu esposa.

Recientemente hubo un hilo sobre cómo hacer este tipo de cosas de forma segura en la lista de python-dev, y las conclusiones fueron:

  • Es muy difícil hacer esto correctamente.
  • Requiere parches al 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 ()? ¿Quieres que un usuario pueda ejecutar expresiones arbitrarias? ¿O estás queriendo transferir datos de alguna manera? Tal vez sea posible bloquear la entrada de alguna manera.

Puede acceder al sistema operativo mediante funciones incorporadas: __import__('os') .

Para Python 2.6+, el módulo ast puede ayudar; en particular ast.literal_eval , aunque depende exactamente de lo que quiera evaluar.

Tenga en cuenta que incluso si pasa diccionarios vacíos a eval (), todavía es posible segfault (C) Python con algunos trucos de syntax. Por ejemplo, pruebe esto con su intérprete: eval("()"*8**5)

Probablemente estés mejor dando la vuelta a la pregunta:

  1. ¿Qué tipo de expresiones quieres evaluar?
  2. ¿Puede asegurarse de que solo las cadenas que coinciden con una syntax estrechamente definida sean eval () d?
  3. Entonces considera si eso es seguro.

Por ejemplo, si desea permitir que el usuario ingrese una expresión algebraica para la evaluación, considere limitarlos a una letra con nombres de variables, números y un conjunto específico de operadores y funciones. No eval () cadenas que contengan cualquier otra cosa.

Hay un artículo muy bueno sobre la no seguridad de eval() en el tutorial Dive into Python de Mark Pilgrim.

Citado de este artículo:

Al final, es posible evaluar con seguridad las expresiones de Python que no son de confianza, para una definición de “seguro” que resulta no ser muy útil en la vida real. Está bien si solo estás jugando, y está bien si solo pasas la entrada de confianza. Pero cualquier otra cosa es solo pedir problemas.