我正在编写一个基于Python的web服务器,该服务器应该能够执行"插件",以便轻松扩展功能。
为此,我考虑了一种方法,即使用多个文件夹(每个插件一个)和多个shell/python脚本,这些脚本以可能发生的不同事件的预定义名称命名。
一个示例是具有当PDF上传到服务器时执行的on_pdf_uploaded.py
文件。为此,我将使用Python的子流程工具。
为了方便和安全,这将允许我使用Unix环境变量来提供进一步的信息,并设置进程的工作目录(cwd),这样它就可以访问正确的文件,而不必找到它们的位置。
由于插件代码来自不受信任的来源,我想让它尽可能安全。我的想法是在一个子流程中执行代码,但将其与另一个用户一起放入chroot监狱,这样它就无法访问服务器上的任何其他资源。
不幸的是,我找不到任何关于这方面的信息,我不想依靠不受信任的脚本把自己关进监狱。
此外,我也不能把主/调用进程放入chroot监狱,因为当服务器回答其他请求时,插件代码可能会同时在多个进程中执行。
因此,问题是:我如何在chroot监狱中以最低权限执行子流程/脚本,以保护服务器的其余部分免受错误、不可信代码的损坏?
谢谢!
也许是这样的?
# main.py
subprocess.call(["python", "pluginhandler.py", "plugin", env])
然后,
# pluginhandler.py
os.chroot(chrootpath)
os.setgid(gid) # Important! Set GID first! See comments for details.
os.setuid(uid)
os.execle(programpath, arg1, arg2, ..., env)
# or another subprocess call
subprocess.call["python", "plugin", env])
编辑:我想使用fork(),但我真的不明白它的作用。查了一下。新密码
# main.py
import os,sys
somevar = someimportantdata
pid = os.fork()
if pid:
# this is the parent process... do whatever needs to be done as the parent
else:
# we are the child process... lets do that plugin thing!
os.setgid(gid) # Important! Set GID first! See comments for details.
os.setuid(uid)
os.chroot(chrootpath)
import untrustworthyplugin
untrustworthyplugin.run(somevar)
sys.exit(0)
这很有用,我几乎只是偷了那个代码,所以作为一个不错的例子,要向那个家伙致敬。
创建你的监狱后,你会从Python源代码中调用os.chroot
来进入监狱。但即使这样,解释器已经打开的任何共享库或模块文件仍然是打开的,我不知道通过os.close
关闭这些文件会有什么后果;我从来没有试过。
即使这样做有效,建立chroot也是一件大事,所以要确保收益物有所值。在最坏的情况下,您必须确保整个Python运行时以及您打算使用的所有模块,以及所有依赖程序、共享库和来自/bin
、/lib
等的其他文件在每个被监禁的文件系统中都可用。当然,这样做不会保护其他类型的资源,即网络目的地、数据库。
另一种选择是将不受信任的代码作为字符串读取,然后读取exec code in mynamespace
,其中mynamespace
是一个字典,只定义要向不受信任代码公开的符号。这将是Python虚拟机中的一个"监狱"。您可能必须首先解析源代码以查找类似import
语句的内容,除非替换内置的__import__
函数会拦截它(我不确定)。