literal ast _fields python eval abstract-syntax-tree

_fields - Usando python''s eval() vs. ast.literal_eval()?



ast python 3 (5)

Tengo una situación con algún código donde eval() surgió como una posible solución. Ahora nunca he tenido que usar eval() antes, pero he encontrado mucha información sobre el peligro potencial que puede causar. Dicho esto, soy muy cauteloso sobre su uso.

Mi situación es que el usuario me ha enviado una entrada:

datamap = raw_input(''Provide some data here: '')

Donde el datamap necesita ser un diccionario. Busqué alrededor y encontré que eval() podría resolver esto. Pensé que podría verificar el tipo de entrada antes de tratar de usar los datos y que sería una precaución de seguridad viable.

datamap = eval(raw_input(''Provide some data here: '') if not isinstance(datamap, dict): return

Leí los documentos y todavía no estoy seguro de si esto sería seguro o no. ¿Eval evalúa los datos tan pronto como se ingresa o después de que se datamap variable del datamap ?

¿Es la opción segura del módulo ast .literal_eval() ?


Python está ansioso en su evaluación, por lo que eval(raw_input(...)) evaluará la entrada del usuario tan pronto como eval la eval , independientemente de lo que haga con los datos después. Por lo tanto, esto no es seguro , especialmente cuando eval la entrada del usuario.

Use ast.literal_eval .

Como ejemplo, ingresar esto en el prompt será muy, muy malo para usted:

__import__(''os'').system(''rm -rf /a-path-you-really-care-about'')


Si todo lo que necesita es un diccionario proporcionado por el usuario, la mejor solución posible es json.loads . La principal limitación es que json dicts requiere claves de cadena. Además, solo puede proporcionar datos literales, pero ese también es el caso de literal_eval .


ast.literal_eval() solo considera que un pequeño subconjunto de la sintaxis de Python es válido:

La cadena o nodo proporcionado solo puede consistir en las siguientes estructuras literales de Python: cadenas, números, tuplas, listas, dictados, booleanos y Ninguno.

Al pasar __import__(''os'').system(''rm -rf /a-path-you-really-care-about'') en ast.literal_eval() producirá un error, pero eval() limpiará felizmente su unidad.

Como parece que solo está permitiendo que el usuario ingrese un diccionario simple, use ast.literal_eval() . Con seguridad hace lo que quiere y nada más.


datamap = eval(raw_input(''Provide some data here: '')) significa que realmente evalúa el código antes de que lo considere inseguro o no. Evalúa el código tan pronto como se llama a la función. Ver también los peligros de eval .

ast.literal_eval genera una excepción si la entrada no es un tipo de datos de Python válido, por lo que el código no se ejecutará si no lo está.

Use ast.literal_eval cada vez que necesite eval . Por lo general, no debería evaluar declaraciones literales de Python.


eval: Esto es muy poderoso, pero también es muy peligroso si acepta cadenas para evaluar desde una entrada no confiable. Supongamos que la cadena que se evalúa es "os.system (''rm -rf /'')"? Realmente comenzará a eliminar todos los archivos en su computadora.

ast.literal_eval: evalúa de forma segura un nodo de expresión o una cadena que contiene un Python literal o una visualización de contenedor. La cadena o nodo proporcionado solo puede consistir en las siguientes estructuras literales de Python: cadenas, bytes, números, tuplas, listas, dictos, conjuntos, booleanos, Ninguno, bytes y conjuntos.

Sintaxis:

eval(expression, globals=None, locals=None) ast.literal_eval(node_or_string)

Ejemplo:

ast.literal_eval("1+1") # output : 2 ast.literal_eval("{''a'': 2, ''b'': 3, 3:''xyz''}") # output : {''a'': 2, ''b'': 3, 3:''xyz''} # type dictionary ast.literal_eval("",{}) # output : Syntax Error required only one parameter ast.literal_eval("__import__(''os'').system(''rm -rf /'')") # output : error eval("__import__(''os'').system(''rm -rf /'')") # output : start deleting all the files on your computer. # restricting using global and local variables eval("__import__(''os'').system(''rm -rf /'')",{''__builtins__'':{}},{}) # output : Error due to blocked imports by passing ''__builtins__'':{} in global # But still eval is not safe. we can access and break the code as given below s = """ (lambda fc=( lambda n: [ c for c in ().__class__.__bases__[0].__subclasses__() if c.__name__ == n ][0] ): fc("function")( fc("code")( 0,0,0,0,"KABOOM",(),(),(),"","",0,"" ),{} )() )() """ eval(s, {''__builtins__'':{}})