我正在开发纯Python的网页游戏,并希望有一些简单的脚本可用于更多动态的游戏内容.特权用户可以实时添加游戏内容.
如果脚本语言可以是Python,那就太好了.但是,由于恶意用户可能会造成严重破坏,因此无法在访问游戏运行环境的情况下运行.是否可以在纯Python中运行沙盒Python?
更新:事实上,由于真正的Python支持会有点过分,因此使用Pythonic语法的简单脚本语言将是完美的.
如果没有任何Pythonic脚本解释器,是否有任何其他开源脚本解释器用纯Python编写,我可以使用?要求是对变量,基本条件和函数调用(不是定义)的支持.
Nou*_*him 44
这真的非常重要.
沙箱Python有两种方法.一种是在这种环境中创建一个受限制的环境(即极少数全局等)和exec你的代码.这就是梅萨所暗示的.这很好但是有很多方法可以打破沙箱并制造麻烦.一年前在Python-dev上有一个关于这个问题的线程,其中人们通过捕获异常并在内部状态进行突破以实现字节代码操作.如果你想要一个完整的语言,这是要走的路.
另一种方法是解析代码,然后使用ast模块踢出你不想要的构造(例如import语句,函数调用等),然后编译其余的.如果你想使用Python作为配置语言等,这是要走的路.
PyPy沙箱是另一种方式(因为你使用GAE可能不适合你).虽然我自己没有使用它,但关于intertubes的话是它是唯一真正的沙盒Python.
根据您对需求的描述(需求是对变量,基本条件和函数调用(不是定义)的支持),您可能希望评估方法2并从代码中删除其他所有内容.这有点棘手,但可行.
dom*_*ecf 17
在最初的问题提出大约十年后,Python 3.8.0 附带了审计功能。有帮助吗?为了简单起见,让我们将讨论限制在硬盘驱动器写入上 - 看看:
from sys import addaudithook
def block_mischief(event,arg):
if 'WRITE_LOCK' in globals() and ((event=='open' and arg[1]!='r')
or event.split('.')[0] in ['subprocess', 'os', 'shutil', 'winreg']): raise IOError('file write forbidden')
addaudithook(block_mischief)
Run Code Online (Sandbox Code Playgroud)
到目前为止exec可以轻松写入磁盘:
exec("open('/tmp/FILE','w').write('pwned by l33t h4xx0rz')", dict(locals()))
Run Code Online (Sandbox Code Playgroud)
但我们可以随意禁止它,这样邪恶的用户就无法通过提供给 的代码访问磁盘exec()。Pythonic 模块喜欢numpy或pickle最终使用 Python 的文件访问,因此它们也被禁止进行磁盘写入。外部程序调用也已被明确禁用。
WRITE_LOCK = True
exec("open('/tmp/FILE','w').write('pwned by l33t h4xx0rz')", dict(locals()))
exec("open('/tmp/FILE','a').write('pwned by l33t h4xx0rz')", dict(locals()))
exec("numpy.savetxt('/tmp/FILE', numpy.eye(3))", dict(locals()))
exec("import subprocess; subprocess.call('echo PWNED >> /tmp/FILE', shell=True)", dict(locals()))
Run Code Online (Sandbox Code Playgroud)
从内部删除锁的尝试exec()似乎是徒劳的,因为审核挂钩使用了不同的副本,locals而 . 运行的代码无法访问该副本exec。请证明我错了。
exec("print('muhehehe'); del WRITE_LOCK; open('/tmp/FILE','w')", dict(locals()))
Run Code Online (Sandbox Code Playgroud)
...
OSError: file write forbidden
Run Code Online (Sandbox Code Playgroud)
当然,顶层代码可以再次启用文件I/O。
del WRITE_LOCK
exec("open('/tmp/FILE','w')", dict(locals()))
Run Code Online (Sandbox Code Playgroud)
事实证明,Cpython 中的沙箱极其困难,之前的许多尝试都失败了。这种方法也不完全安全,例如对于公共网络访问:
也许 Cpython 无法审核使用直接操作系统调用的假设编译模块 - 建议将安全的纯 pythonic 模块列入白名单。
当然,Cpython 解释器仍然有可能崩溃或过载。
也许甚至还存在一些将文件写入硬盘的漏洞。但我无法使用任何常见的沙箱规避技巧来写入单个字节。我们可以说 Python 生态系统的“攻击面”减少到了一个狭窄的允许(禁止)事件列表:https ://docs.python.org/3/library/audit_events.html
我将感谢任何指出我这种方法的缺陷的人。
编辑:所以这也不安全!我非常感谢@Emu 使用异常捕获和内省的巧妙技巧:
#!/usr/bin/python3.8
from sys import addaudithook
def block_mischief(event,arg):
if 'WRITE_LOCK' in globals() and ((event=='open' and arg[1]!='r') or event.split('.')[0] in ['subprocess', 'os', 'shutil', 'winreg']):
raise IOError('file write forbidden')
addaudithook(block_mischief)
WRITE_LOCK = True
exec("""
import sys
def r(a, b):
try:
raise Exception()
except:
del sys.exc_info()[2].tb_frame.f_back.f_globals['WRITE_LOCK']
import sys
w = type('evil',(object,),{'__ne__':r})()
sys.audit('open', None, w)
open('/tmp/FILE','w').write('pwned by l33t h4xx0rz')""", dict(locals()))
Run Code Online (Sandbox Code Playgroud)
我想审计+子处理是可行的方法,但不要在生产机器上使用它:
https://bitbucket.org/fdominec/experimental_sandbox_in_cpython38/src/master/sandbox_experiment.py
AFAIK可以在完全隔离的环境中运行代码:
exec somePythonCode in {'__builtins__': {}}, {}
Run Code Online (Sandbox Code Playgroud)
但是在这样的环境中你几乎什么也做不了:)(你甚至不能import用模块;但是仍然是恶意用户可以运行无限递归或导致内存不足.)可能你会想要添加一些模块作为接口给你游戏引擎.
我不确定为什么没有人提到这一点,但是Zope 2有一个叫做Python脚本的东西,正是这样-受限制的Python在沙箱中执行,无需访问文件系统,也可以访问由Zope安全机制控制的其他Zope对象,进口仅限于安全子集。
总的来说,Zope非常安全,因此我可以想象没有已知或明显的方法可以突破沙盒。
我不确定Python脚本的实现方式如何,但是该功能自2000年以来就存在。
这是PythonScripts背后的魔力,带有详细的文档:http ://pypi.python.org/pypi/RestrictedPython- 甚至看起来它与Zope无关,因此可以独立使用。
请注意,这不是为了安全地运行任意python代码(大多数随机脚本在首次导入或访问文件时都会失败),而是为了在Python应用程序中使用Python进行受限脚本编写。
这个答案是从我的评论开始的,这个问题的解决是与以下问题的重复:一个Python的Python:限制功能吗?