¿Qué hay de Python itself?
Por ejemplo:
>>> import code
>>> def host_func():
... print("Hello old chap!")
...
>>> c = code.compile_command("print(\"Script says hello!\"); host_func()")
>>> exec(c)
Script says hello!
Hello old chap!
exec
de dejará ser explícito acerca de lo que desde el entorno de host que desea exponer a través de los dos parámetros opcionales locals
y globals
.
En este ejemplo estoy siendo explícito acerca de lo que la secuencia de comandos globales tendrán acceso a. Tenga en cuenta que puedo "crear" variables aquí, o darle otro nombre a las funciones existentes. Es un diccionario que apunta a funciones y datos.
>>> import code
>>> def secret():
... print("What?! I don't even... get out of here.")
...
>>> def public():
... print("Hello stranger.")
...
>>> c = code.compile_command("secret(); public()")
Al llamar a este con variables globales que contienen dos funciones, que apuntan de nuevo a los ya existentes da:
>>> exec(c, {"secret": secret, "public": public})
What?! I don't even... get out of here.
Hello stranger.
Ahora, cuando Omito secret
, el guión ya no puede encontrarlo.
>>> exec(c, {"public": public})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<input>", line 1, in <module>
NameError: name 'secret' is not defined
Aquí redefino secret
todos juntos:
>>> exec(c, {"public": public, "secret":lambda: print("Haha! Doppelganger.")})
Haha! Doppelganger.
Hello stranger.
Como lazyr menciones en los comentarios hay preocupaciones de seguridad. Los ejemplos anteriores permiten que la secuencia de comandos prácticamente haga lo que quiera. En algunos casos esto no es aceptable.
Hay algunas cosas que uno puede hacer para desalentarlo:
- neutro
__builtins__
, sólo permiten funciones "lista blanca" incorporados.
- hacer que sea difícil para importar módulos.
Por ejemplo, así es como se escribe la declaración import
(en Py2.* Builtins es __builtins__
):
>>> import builtins
>>> def no_import(*args, **kwargs):
... raise ImportError("I cannot let you do that, Dave.")
...
>>> builtins.__import__ = no_import
>>> import os
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in no_import
ImportError: I cannot let you do that, Dave.
De esto se sigue que podemos pasar nuestra propia builtins
en el parámetro globales:
>>> import code
>>> evil_code = "import os; import stat; os.chmod(\"passwords.txt\", stat.S_IROT
H);"
>>> compiled = code.compile_command(evil_code)
>>> def no_import(*args, **kwargs):
... raise ImportError("I cannot let you do that, Dave.")
...
>>> exec(compiled, {"__builtins__": {"__import__": no_import}})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<input>", line 1, in <module>
File "<stdin>", line 2, in no_import
ImportError: I cannot let you do that, Dave.
Una advertencia, sin embargo, esto será Bork todas las importaciones que tienen lugar después de ella. Puede ser mejor reemplazarlo con una versión que le permita importar módulos incluidos en la lista blanca.
Y, por último, no estoy seguro de que esto te proteja por completo. Alguna persona astuta puede eludirlo. Pero las infracciones más flagrantes deberían al menos desalentarse.
+1 Así que superas el hito de la reputación de 5000. Tal vez debería mencionar algo sobre las preocupaciones de seguridad? 'abrir ("/importante/archivo "," w "). escribir (" cosas ")' etc. –
@lazyr: Oh gracias: D ... lo celebraré con torta. Sí, estaba pensando en eso. Podría agregar un punto al respecto. – Skurmedel
La pared del texto me critica por más de 400 daños. – Skurmedel