禁止在Python中访问exec和eval中的文件系统

jcu*_*bic 4 python filesystems eval sandbox exec

我想禁止从客户端代码访问文件系统,所以我想我可以覆盖open函数

env = {
   'open': lambda *a: StringIO("you can't use open")
}

exec(open('user_code.py'), env)
Run Code Online (Sandbox Code Playgroud)

但我得到了这个

unqualified exec is not allowed in function 'my function' it contains a 
nested function with free variables
Run Code Online (Sandbox Code Playgroud)

我也试试

 def open_exception(*a):
     raise Exception("you can't use open")
 env = {
     'open': open_exception
 }
Run Code Online (Sandbox Code Playgroud)

但得到了同样的例外(不是"你不能用开")

我想防止:

执行此:

"""def foo():
     return open('some_file').read()
print foo()"""
Run Code Online (Sandbox Code Playgroud)

并评估这一点

"open('some_file').write('some text')"
Run Code Online (Sandbox Code Playgroud)

我还使用session来存储之前评估过的代码,所以我需要阻止执行这个:

"""def foo(s):
   return open(s)"""
Run Code Online (Sandbox Code Playgroud)

然后评估这个

"foo('some').write('some text')"
Run Code Online (Sandbox Code Playgroud)

我不能使用正则表达式因为有人可以使用(eval在字符串中)

"eval(\"opxx('some file').write('some text')\".replace('xx', 'en')"
Run Code Online (Sandbox Code Playgroud)

有没有办法阻止访问exec/eval中的文件系统?(我需要两个)

Ros*_*ron 11

没有办法阻止访问exec/eval中的文件系统.这是一个示例代码,演示了用户代码调用总是有效的其他受限类的方法:

import subprocess
code = """[x for x in ().__class__.__bases__[0].__subclasses__() 
           if x.__name__ == 'Popen'][0](['ls', '-la']).wait()"""
# Executing the `code` will always run `ls`...
exec code in dict(__builtins__=None)
Run Code Online (Sandbox Code Playgroud)

并且不要考虑过滤输入,特别是使用正则表达式.

您可以考虑一些替代方案:

  1. ast.literal_eval 如果你只能将自己局限于简单的表达方式
  2. 使用另一种语言的用户代码.您可能会看一下Lua或JavaScript - 它们有时用于在沙箱中运行不安全的代码.
  3. pysandbox项目,但我不能保证沙盒代码真的很安全.Python不是设计为沙盒的,特别是CPython实现并不是用沙盒编写的.甚至作者似乎也怀疑安全地实施这种沙箱的可能性.


lun*_*orn 5

您不能打开exec()eval()进入安全沙箱.只要sys模块可用,您始终可以访问内置模块::

sys.modules[().__class__.__bases__[0].__module__].open
Run Code Online (Sandbox Code Playgroud)

即使sys不可用,您仍然可以通过基本相同的方式访问任何导入模块中定义的任何新样式类.这包括所有IO类io.


the*_*aul 5

这实际上可以做到.

也就是说,实际上你所描述的内容可以在Linux上完成,与此处的其他答案相反.也就是说,您可以实现一种设置,在该设置中您可以进行类似exec的调用,该调用在安全性下运行不受信任的代码,这些代码难以渗透,并且允许输出结果.除了读取Python vm和标准库的特定允许部分之外,不允许不受信任的代码访问文件系统.

如果它足够接近您想要的,请继续阅读.

我正在构想一个系统,在这个系统中,类似exec的函数会在非常严格的AppArmor配置文件下生成子流程,例如Straitjacket使用的配置文件(请参见此处此处).这将限制内核级别的所有文件系统访问,而不是特别允许读取的文件.这还将限制进程的堆栈大小,最大数据段大小,最大驻留集大小,CPU时间,可排队的信号数以及地址空间大小.该进程将锁定内存,内核,flock/fcntl锁,POSIX消息队列等,完全不允许.如果你想允许在临时区域使用的大小限制的临时文件,可以mkstemp并使其提供给子进程,并允许写有在一定条件下(确保硬链接是绝对不允许的).您希望确保清除子进程环境中的任何有趣内容并将其放入新的会话和进程组中,并关闭除了stdin/stdout/stderr之外的子进程中的所有FD,如果要允许与那些.

如果您希望能够从不受信任的代码中取出Python对象,可以将其包装在将结果打印repr到stdout的内容中,并在检查其大小后,使用它进行评估ast.literal_eval().这严重限制了可以返回的对象的可能类型,但实际上,任何比这些基本类型更复杂的东西都可能存在意图在您的进程中触发的sekrit恶意攻击的可能性.在任何情况下都不应该使用pickle进程之间的通信协议.