在Python中使用subprocess.run()运行脚本,阻止所有文件读/写尝试

pjngdqdw  于 12个月前  发布在  Python
关注(0)|答案(1)|浏览(143)

我有一个Web服务器上运行Apache 2 Raspbian Stretch.这将是一个编程竞赛网站,用户可以通过HTML表单发送代码,通过POST请求将源代码发送给PHP。(使用exec())带有参数(如提交的代码路径)的Python脚本。然后脚本执行代码(使用subprocess.run())与自定义输入进行比较,并将其与预期输出进行比较。所有这些都很好。
但是,我想确保没有人会发送恶意代码来覆盖文件,如index.php,或读取预期的输出,例如,我想知道是否有任何方法可以防止由subprocess.run()执行的应用程序阅读,创建和写入stdinstdoutstderr以外的文件。
我试过使用Docker,但没有用,我想尽可能避免Docker,因为它将在Raspberry Pi上运行,所以RAM的使用是一个问题。
我正在考虑使用chroot监狱,但我仍然在寻找其他不那么复杂的方法。
这是我正在使用的PHP代码。它调用Python 3代码验证器(变量从HTML表单和SQL查询中检索,这些都不相关):

$cmd = "python3 verify.py $uploadedFile $questionID $uploadedFileExtension $questionTimeLimit 2>&1";

字符串
这是执行提交的代码的Python 3代码:

def run_cmd(args, v_stdin, timelimit=10):
    p = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, input=v_stdin, encoding='utf-8', timeout=timelimit)
    return p.stdout.strip(), p.stderr.strip()

# ...

out, err = run_cmd(['python3', sys.argv[1], 'example-input.in', int(sys.argv[4]))

# ...


这两个程序的组合可以正常工作。它使用虚拟输入运行代码,比较输出并向PHP返回状态。但是,代码可能包含恶意内容:

open('/var/www/html/contest/index.php', 'w').write('oops!') # rip index.php :(


我所需要的是一种执行用户发送的代码的方式,它试图读取或写入文件(除了stdinstdoutstderr)被拒绝。
有什么想法吗?

5anewei6

5anewei61#

简单地说,安全地做这件事是很困难的。如果你不小心如何设置它,即使是chroot监狱也相对容易逃脱。基本上,Unix安全模型并不是为了让这类事情变得容易而构建的,它假设事情主要是合作的。
docker可能是我的建议,但也有其他轻量级的解决方案,如chroot(但他们可能仍然有能力做一些顽皮的事情与web服务器的网络连接),或者像firejail
使用docker,你可能想创建一个最小的docker镜像/容器,包含Python和任何合适的库。然后你可以使用volumes使用户提供的代码在运行时出现在VM中。你不想一直创建容器,这将需要大量的清理工作
请参阅https://security.stackexchange.com/q/107850/36536了解更多关于使用docker作为沙箱的信息,基本上仍然有很多方法,除非你小心

相关问题