Usando eval() de Python versus ast.literal_eval()

Resuelto tijko asked hace 11 años • 6 respuestas

Tengo una situación con algún código que eval()surgió como posible solución. Nunca antes había tenido que consumirlo eval(), pero he encontrado mucha información sobre el peligro potencial que puede causar. Dicho esto, soy muy cauteloso al usarlo.

Mi situación es que un usuario me ha dado una entrada:

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

¿ Dónde datamaptiene que haber un diccionario? Busqué por ahí y descubrí que eval()esto podía solucionarlo. Pensé que podría comprobar el tipo de entrada antes de intentar utilizar los datos y que sería una medida de seguridad viable.

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

Leí los documentos y todavía no tengo claro si esto sería seguro o no. ¿Eval evalúa los datos tan pronto como se ingresan o después datamapde llamar a la variable?

¿ Es el astmódulo .literal_eval()la única opción segura?

tijko avatar Mar 04 '13 15:03 tijko
Aceptado

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

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

Úselo ast.literal_evalcuando lo necesite eval. Por lo general, no deberías evaluar declaraciones literales de Python.

Volatility avatar Mar 04 '2013 08:03 Volatility

ast.literal_eval()sólo considera válido un pequeño subconjunto de la sintaxis de Python:

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

__import__('os').system('rm -rf /a-path-you-really-care-about')Al pasar ast.literal_eval()a generará un error, pero eval()felizmente eliminará sus archivos.

Dado que parece que solo le permite al usuario ingresar un diccionario simple, use ast.literal_eval(). Hace de forma segura lo que quieres y nada más.

Blender avatar Mar 04 '2013 08:03 Blender

eval: esto es muy poderoso, pero también muy peligroso si acepta cadenas para evaluar desde entradas que no son de confianza. Supongamos que la cadena que se está evaluando es "os.system('rm -rf /')". Realmente comenzará a eliminar todos los archivos de su computadora.

ast.literal_eval: evalúa de forma segura un nodo de expresión o una cadena que contiene un literal de Python 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, dictados, conjuntos, booleanos, Ninguno, bytes y conjuntos.

Sintaxis:

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

Ejemplo:

# python 2.x - doesn't accept operators in string format
import ast
ast.literal_eval('[1, 2, 3]')  # output: [1, 2, 3]
ast.literal_eval('1+1') # output: ValueError: malformed string


# python 3.0 -3.6
import ast
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__':{}})

En el código anterior ().__class__.__bases__[0]nada más que el objeto mismo. Ahora creamos instancias de todas las subclases , aquí nuestro enter code hereobjetivo principal es encontrar una clase llamada n a partir de ella.

Necesitamos codeobjetar y functionobjetar desde subclases instanciadas. Esta es una forma alternativa de CPythonacceder a subclases de objetos y adjuntarlos al sistema.

Desde Python 3.7, ast.literal_eval() ahora es más estricto. Ya no se permiten la suma y resta de números arbitrarios. enlace

Kiran Kumar Kotari avatar Jan 20 '2016 15:01 Kiran Kumar Kotari