¿Qué tan segura es la evaluación de expresiones usando eval?

Estoy creando un sitio web en el que tengo la necesidad de que el usuario pueda evaluar algunas expresiones basadas en el valor de las tablas de DB, en lugar de usar herramientas como pyparsing, etc., estoy pensando en usar Python en sí y he encontrado una solución. lo cual es suficiente para mi propósito. Básicamente, estoy usando eval para evaluar la expresión y pasar los __builtins__ globales con __builtins__ vacío para que no se pueda acceder a nada y un dictamen de los locales para los valores de DB, si el usuario necesita algunas funciones, también puedo __builtins__ por ejemplo.

 import datetime def today(): return datetime.datetime.now() expression = """ first_name.lower() == "anurag" and today().year == 2010 """ print eval(expression, {'__builtins__':{}}, {'first_name':'Anurag', 'today':today}) 

Así que mi pregunta es qué tan seguro sería, tengo tres criterios

  1. ¿El usuario puede acceder al estado actual de mi progtwig o tabla, etc.?
  2. ¿El usuario puede tener acceso a llamadas de nivel OS?
  3. El usuario puede detener mi sistema haciendo un bucle o utilizando mucha memoria, por ejemplo, haciendo rango (10 * 8), en algunos casos puede, por ejemplo, 100 ** 1000, etc., por lo que 3 no es tanto un problema. Puedo verificar tal operación con tokenize y de todas formas estaré usando GAE, así que no es una gran preocupación.

Edición : OMI, este no es el duplicado de Q: 661084 porque donde termina éste, quiero saber, incluso con __builtins__ bloqueado, ¿el usuario puede hacer cosas malas?

Es completamente inseguro usar eval , incluso con las __class__ integradas vacías y bloqueadas: el atacante puede comenzar con un literal, obtener su __class__ , etc, etc., hasta el object , sus __subclasses__ , y así sucesivamente … básicamente, la introspección de Python es demasiado fuerte para enfrentar a un atacante hábil y determinado.

ast.literal_eval es seguro, si puedes vivir de acuerdo con sus limitaciones …

Ciertamente, es posible consumir toda la memoria disponible o crear un bucle infinito incluso sin los elementos integrados. Hay muchas maneras de hacerlo como ‘a’ * 999999 * 999999 o hacer un bucle infinito:

 >>> print eval('[[x.append(a) for a in x] for x in [[0]]]', ... {'__builtins__':{}}, {'first_name':'Anurag', 'today':today}) 

En cuanto a 1) y 2), no estoy seguro pero parece arriesgado. Aquí hay una cosa que intenté y pensé que funcionaría, pero parece que alguien más ya consideró esa línea de ataque y la bloqueó:

 >>> import datetime >>> def today(): >>> return datetime.datetime.now() >>> >>> print eval('today.func_globals', {'__builtins__':{}}, {'first_name':'Anurag', 'today':today}) RuntimeError: restricted attribute 

Estaba medio esperando conseguir esto en su lugar:

 {'__builtins__': , ... 

Así que creo que es probablemente una mala idea. Solo necesita un pequeño orificio y le da acceso a todo su sistema. ¿Has considerado otros métodos que no usan eval? ¿Que hay de malo con ellos?

Es posible crear e invocar cualquier clase definida en el progtwig, que incluye aquellas que pueden salir del intérprete de Python. Además, puede crear y ejecutar cadenas arbitrarias de bytecode, que pueden segregar al intérprete. Ver Eval realmente es peligroso para todos los detalles.