一个解决方法是创建一个白名单,列出可以用于读取文件系统、数据库或网络的Python库。但如果采用这种方法,从哪里获取这个(可能很大)列表呢?此外,我不想禁用整个库,只因为它可以用于读取文件系统。例如,我希望用户能够使用pandas库(存储和操作表格数据),但不希望他们能够使用该库从文件系统中读取数据。
这个问题是否有解决方案?
答案是否定的。您需要寻找一个测试 函数纯度
的函数。但是,正如此代码所示,无法保证不会实际调用任何副作用。
class Foo(object):
def __init__(self, x):
self.x = x
def __add__(self, y):
print("HAHAHA evil side effects here...")
# proceed to read a file and do stuff
return self
# this looks pure...
def f(x): return x + 1
# but really...
>>> f(Foo(1))
HAHAHA evil side effects here...
由于对象可以全面重新定义它们的行为(字段访问、调用、操作符重载等),因此您始终可以传递一个使纯函数变成不纯的输入。因此,唯一的纯函数是那些字面上不对其参数进行任何操作的函数...这类函数通常不太有用。
当然,如果您可以指定其他限制,这将变得更加容易。
即使你删除所有模块和所有函数,也可以打破您所需的限制。如果代码可以使用任意简单对象的属性,例如数字零的属性,则可以访问文件。
(0).__class__.__base__.__subclasses__()[40]('/etc/pas'+'swd')
索引40
是Python 2.7的特点之一,但是子类<type 'file'>
的索引可以很容易地找到:
[x for x in (1).__class__.__base__.__subclasses__()if'fi'+'le'in'%s'%x][0](
'/etc/pas'+'swd')
白名单和黑名单的任何组合都不安全和/或过于限制性。 pypy沙箱 的原则是坚不可摧的:
... 此子进程可以运行任意不受信任的Python代码,但其所有输入/输出都序列化为stdin / stdout管道,而不是直接执行。外部进程读取管道并决定允许或不允许哪些命令(沙盒化),甚至以不同方式重新解释它们...
此外,基于seccomp内核功能的解决方案足够安全。(博客)
我想确保在未来该函数将生成与今天相同的输出。
编写具有固定可重现结果且不易被阻止的函数非常容易:
class A(object):
"This can be any very simple class"
def __init__(self, x):
self.x = x
def __repr__(self):
return repr(self.x)
def strange_function():
# You get a different result probably everytimes.
return list(set(A(i) for i in range(20)))
>>> strange_function()
[1, 18, 12, 5, 16, 15, 8, 2, 14, 0, 6, 19, 13, 11, 10, 9, 17, 3, 7, 4]
>>> strange_function()
[0, 9, 14, 3, 17, 5, 6, 11, 8, 1, 15, 7, 12, 13, 2, 10, 16, 4, 19, 18]
您无需关心内部调用,只需全局输入和输出,直到找到差异为止。虚拟机应能够独立且可重复地验证结果。配置防火墙,使该机器接受您的连接,但不能发起出站连接。配置文件系统,使当前用户无法保存数据,因此除软件组件外,它们不存在。禁用数据库服务。以随机顺序验证结果输入/输出,或在不同端口上启动两个IPython笔记本服务,并为笔记本上的每个命令行选择随机后端,或在重要事项之前频繁重新启动后端进程。如果发现差异,请调试您的代码并修复它。
如果您不需要交互性,则可以最终使用IPython远程计算自动化它而不使用“笔记本”。
class A:pass;str(A)
- PythonNut
pysandbox
)。PyPy 支持此功能,但我不知道还有其他确实安全的选择。 - dano