Python itself 怎么样?
例如:
>>> 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 让您通过两个可选参数locals 和globals 明确说明要从主机环境中公开的内容。
在这个例子中,我明确说明了脚本可以访问哪些全局变量。请注意,我可以在这里“创建”变量,或者给现有函数另一个名称。它是一个指向函数和数据的字典。
>>> 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()")
用包含两个函数的全局变量调用它,指向已经存在的函数给出:
>>> exec(c, {"secret": secret, "public": public})
What?! I don't even... get out of here.
Hello stranger.
现在当我省略 secret 时,脚本将无法再找到它。
>>> 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
在这里我重新定义secret一起:
>>> exec(c, {"public": public, "secret":lambda: print("Haha! Doppelganger.")})
Haha! Doppelganger.
Hello stranger.
正如lazyr 在 cmets 中提到的,存在安全问题。上面的例子让脚本几乎可以做它想做的事。在某些情况下,这是不可接受的。
有一些事情可以阻止它:
- 中性
__builtins__,仅允许“列入白名单”的内置函数。
- 使导入模块变得困难。
例如,下面是你如何使用 import 语句(在 Py2.* 内置函数中是 __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.
由此我们可以在 globals 参数中传递我们自己的builtins:
>>> 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.
但是,需要注意的是,这将阻止在它之后发生的所有导入。将其替换为可让您导入列入白名单的模块的版本可能会更好。
最后,我不确定这是否能完全保护你。一些狡猾的人很可能会绕过它。但至少应该劝阻最公然的违规行为。