如何安全地运行不受信任的Python代码?

5
这是场景:我的网站有一些不安全的代码,由网站用户生成,运行在我的服务器上。
我想禁用一些保留字对Python进行保护,例如evalexecprint等等。
有没有一种简单的方法(不修改Python解释器,我的Python版本是2.7.10),可以实现我之前描述的功能?
非常感谢。

你的网站是一开始就被设计成沙盒吗?还是因为有人试图攻击你的网站而发生了这种情况? - Burhan Khalid
在处理任何内容之前,您可以验证用户输入。 - Hackaholic
eval不是关键字,而是一个函数。eval = 8; print eval。验证代码的最佳方法是将其解析为AST,然后扫描树以查找不安全的内容。但是...请参见此处 - Amadan
感谢提醒关于 eval 的问题和建议。 - diaosihuai
说到eval,可以看看Stack Overflow老手Ned Batchelder的文章《Eval真的很危险》。该文章中有一些评论讨论使用ast模块来清理用户提供的代码。 - PM 2Ring
显示剩余3条评论
2个回答

4

禁用Python的名称在Python级别上是无效的,因为有很多绕过方法。请参考文章获取更多信息。以下是您需要执行的操作:

对于CPython,请使用RestrictedPython定义Python受限子集。

对于PyPy,请使用沙箱模式。它允许您在特殊环境中运行任意的Python代码,以序列化所有输入/输出,从而可以在实际运行之前检查并决定哪些命令是允许的。

自版本3.8起,Python支持审计钩子,因此您可以完全防止某些行为:

import sys

def audit(event, args):
    if event == 'compile':
        sys.exit('nice try!')

sys.addaudithook(audit)

eval('5')

此外,为了保护您的主机操作系统,请使用以下方法:

  • 虚拟化(更安全)例如 KVM 或 VirtualBox

  • 或容器化(更轻)例如 lxddocker

如果您选择使用 docker 进行容器化,则可能需要添加 AppArmor 或 SELinux 策略以提高安全性。 lxd 默认已经带有 AppArmor 策略。

请确保使用权限最低的用户运行代码。

对于每个用户,请重新构建虚拟机/容器。

无论您选择哪种解决方案,都不要忘记限制资源使用量(RAM、CPU、存储、网络)。如果您所选的虚拟化/容器化方案不支持此类限制,请使用 cgroups

最后,使用超时来防止用户的代码永远运行。


0
一种方法是使用阴影方法:
def not_available(*args, **kwargs):
    return 'Not allowed'

eval = not_available
exec = not_available
print = not_available

然而,聪明的人总是可以做到这一点:

import builtins
builtins.print('this works!')

因此,真正的解决方案是解析代码,如果有这样的语句,则不允许输入(而不是尝试禁用它们)。

很好!我也尝试禁用一些特定的模块,比如os、threading和builtins... - diaosihuai
1
不幸的是,这对于Python 2.7中的exec不起作用,因为exec是一个语句而不是函数,所以任何尝试分配给exec都会引发SyntaxError:invalid syntax。 而要使其适用于print,您需要使用from __future__ import print_function来禁用print语句。 - PM 2Ring
@diaosihuai:你可以进行简单的字符串或正则表达式测试,以查看用户代码是否包含exec语句。另一方面,最好使用ast来处理用户代码。 - PM 2Ring
@PM 2Ring 使用ast检查用户代码是否包含这些敏感关键词,如果结果为True,则停止。因此,用户代码在通过ast测试之前不会真正运行? - diaosihuai

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接