2026年7月2日 周四晚上19:30,报名腾讯会议了解“如何构建自进化的动态知识库(Brain)”(限30人)
免费POC, 零成本试错
FDE知识库

FDE知识库

学习大模型的前沿技术与行业落地应用


收藏

DifySandbox 的构建背景和实现机制

发布日期:2024-07-12 10:10:59 浏览次数: 9034
作者:Dify

微信搜一搜,关注“Dify”

Hello,这里是 Dify 的后端工程师 Yeuoly,也是 DifySandbox 的作者。对于 Dify 的社区用户来说,应该对一个叫做 Sandbox 的 docker 服务不陌生,我们也收到过很多关于 Sandbox 的反馈,但是绝大多数用户对于 Sandbox 本身非常陌生,并不清楚 Sandbox 的内部细节,而这篇文章将会让你逐渐了解 Sandbox 内部究竟发生了什么。

DifySandbox:基于执行代码和系统安全需求

在 Dify 中,Workflow 是一项重要的能力,它允许用户以拖拉拽的方式来编排一个逻辑流,从而实现相对复杂的业务逻辑,在编排逻辑的过程中,复杂的数据处理是必不可少的,具体来说,我们可能有下面这些场景:

  • 有时候我们需要处理 LLM 生成的 JSON 文本,从中提取结构化的数据,有时候又需要处理 HTTP 请求返回的 XML 文本、JSON 文本。

  • 在另外一些场景下,甚至需要合并两个知识检索节点的输出内容,亦或者是合并知识检索节点 GoogleSearch 的结果。

  • 甚至一些情况,具备编码基础的用户想要使用一些例如 Jinja2 和 Liquid 这样的模板语法,从而可以实现更灵活的 prompt 编排。

上述的这些场景是多而杂的,但是究其根本仍然是数据处理,它们需要一个统一的解决方案,那么自然而然的我们就会想到写代码来实现,因为相比于数据处理节点这类高度定制化的实现,代码显然会更通用,如果给用户提供一个代码编辑框,在编辑框内,用户可以通过编写自己的代码来实现数据处理逻辑,那么这些问题就都迎刃而解。

既然需要在 Dify 中执行用户编写的代码,自然而然就需要考虑安全的问题,面对恶意用户的时候,代码执行就不再是一个正常功能,而变成了一个漏洞。

在理想情况下,用户编写的代码大多都是非恶意的代码,如果直接由 Dify 来执行代码,那么其实就是让 Dify 在服务器上创建一个新的 Python、Nodejs 进程,并将用户的代码提交到这个进程里去执行,就像下面这样,Process 就是执行代码的进程,User 需要首先访问 Dify,再由 Dify 来访问 Process。

而在恶意用户的手上,上面这个过程就会出现问题,Process 是直接运行在服务器上的,这会造成 Process 可以访问文件系统和数据库,那么此时就变成了下面这样了,用户编写的代码可以任意读取服务器上的文件,甚至在极端情况下可以读取或者删除整个 Dify 的数据库。

正是因为这样的问题,Dify 自研了 DifySandbox,它是一套代码沙箱方案,可以有效拦截恶意代码的操作,并放行正常业务逻辑,下面我们将详细介绍 Sandbox。

DifySandbox 的设计思路和实现机制

在设计之初,我们从几个角度考虑了 Sandbox 所需要满足的安全性能:

  1. 我们考虑了全球开发者不同的编码倾向,总得来看,在 LLM 的生态里,Python 和 Nodejs 两者是绝对的 Top2,同时,我们也不希望强制用户编写 Python 或者 Nodejs,因此,我们希望将两者都提供给大家,所以 Sandbox 的技术方案不能局限于某一个语言,应该有一个在系统层级上的解决方案。
  2. Sandbox 存在被绕过的可能性吗?这肯定是无法绝对避免的,世界上没有绝对安全的系统,因此我们不能将安全性完全依赖于 Sandbox 本身,应该做到即使 Sandbox 存在漏洞,黑客也无法访问核心资源。
  3. 网络是一个老大难的问题,它的影响是方方面面的:

    1. 生产中很多的沙盒绕过都是通过网络,如 VMWare 虚拟机,它挺多的漏洞都是通过网络来实现的。

    2. 即使在代码层面、系统层面实现了防护,仍然阻止不了恶意代码通过网络来嗅探内网,从而非法访问内网资源,因此 Sandbox 还需要考虑如何隔离网络。

同时,我们也调研了市面上现有的一些沙盒方案,它们和其优缺点大概如下:
  1. WebAssembly:这是一个目前大多数沙盒的方案,通过将 Python、Nodejs 的解释器编译为一个 WebAssembly 的运行时,从而可以在 Nodejs 中或者浏览器中运行 Python 代码,在确保规范使用 WebAssembly 的情况下,这个方案在系统层面是非常安全的,但是它带来的问题就是自由度不够高,比如说如果需要安装第三方依赖,那么这样做起来就会有非常多像架构不兼容这样的深坑,并且要同时为 Python 和 Nodejs 做不同的处理,并不是一个特别灵活的方案。
  2. Docker:有一些厂家使用了运行一次代码就新建一个 Docker 容器的做法,这样做的自由度肯定是非常高的,但是代价就是运行速度极慢,运行一次代码需要 1s+ 的时间,最终在 workflow 上体现出来可能就是 10 个代码节点就消耗了  10s+ 的时间,这样的代价实在是太大,同时,这个方案还需要管理容器,需要将docker daemon的sock挂载到 Dify 的 api 容器中,这带来了极大的安全隐患,或者使用docker in docker的解决方案,但是这就更慢了,不是一个理想的解决方案。
  3. 特定语言的沙盒包:Nodejs 下有 vm2,Python 下有 Pypy,但是他们都限制在了某一个语言上,并且都有各自的限制,并不是一个通用方案,并且他们在处理依赖的时候也需要按照其规范处理,以及像 Pypy 的 Python 版本也有严格的限制,依赖也不是那么得方便,当然这里还存在一些其他的库,如 pyodide,不过最大的问题还是 Nodejs 和 Python 的方案不通用,维护起来有一定难度。
  4. 内核扩展:一些比较老牌的沙盒会采用在内核安装扩展来限制进程行为,并且都配有极其复杂的配置文档,启动过程也非常复杂,如 Sandboxie 和 judge0,他们都是内核的方案,但 judge0 就曾因为配置问题出现过一个及其严重的 CVE,并且它是牵一发动全身的,内核扩展要求特权容器,这导致了一旦绕过它的限制,docker 的限制也会变得没有意义。

我们感觉到目前的方案都不是非常契合 Dify 本身的业务,都有多多少少不能满足我们需要的地方,如运行太慢或者某个语言特点或者存在潜在的安全隐患,因此我们最后选择了自研一套方案,其大概的画像如下:
  1. 多层的隔离:理所当然的大家都会想到 Docker 容器,当然,我们也这么做了,这也可以给到用户十足的安全感,只是我们只在 Dify 启动阶段开启一个 sandbox 容器,它内部会维护一个 http 服务,接收来自 Dify 的代码执行请求,并不会每次有一个任务就新建一个 Docker 容器,不过这也限制系统在了 Linux 上,而在 Windows、Mac 等平台就需要 DockerDesktop、Orbstack 等工具。
  2. 系统层级的隔离:Linux 上的系统沙箱方案最常见的其实是 Docker,但是我们已经套了一层 Docker 了,因此我们需要再进一步,使用 Docker 的底层依赖的一项技术:Seccomp。
    可以将 Seccomp 看做是一个过滤器,它会过滤所有尝试访问系统的请求,包括但不限于读写文件、修改系统配置、网络访问,甚至是标准输入输出,都会经过 Seccomp,因为这些操作本质上都是一个个system call (syscall),一个 syscall 就是一次对系统的访问,其流程如下:

通过设置 Seccomp,我们就可以做到在一个进程尝试进行任何非法 syscall 时拦截其行为,最常见的,拦截文件访问、进程创建、磁盘 mount、系统修改。

然而,在不同的芯片架构上,有完全不同的 syscall 体系,并且 syscall 的数量非常庞大,如写文件的系统调用编号在 amd64 上是 2,但是在 arm64 上就是 64,amd64上有 300+系统调用,但是 arm64 上就有 400+,如果用黑名单的策略很有可能出现有哪个系统调用被意外放行,这会导致很严重的安全隐患,因此 DifySandbox 采用了白名单的策略,只放行必要的权限,所有非必要权限都进行拦截。

1. 在文件层面,我们还需要为 Sandbox 的子进程虚拟一套文件系统,将 Sandbox 宿主容器的文件系统和 Sandbox 中运行用户代码的进程的文件系统隔离开来,主要原因是 Seccomp 只能允许或禁止对所有文件的访问,如果粒度更细一些,就是需要一些文件可以被正常访问,如 Python 的第三方依赖,但是另一些文件不能被访问,如 /etc/passwd 等敏感文件,综上,我们需要隔离一个独立的文件系统出来,这就是 Linux 中的 chroot (change root),它可以更改一个进程的根目录到一个临时目录下,比如说我们在 Python 进程中执行了 chroot ("/tmp") 以后,这个 Python 进程再 ls / 看到的就都是原本 /tmp 下的文件,它可以有效隔离文件系统,如下图所示,每一个 sandbox 文件夹最后都会变成某一个 sandbox 进程的根目录。

但是 chroot 存在一些小的绕过问题,如果再次 chroot 到一个子文件夹下,就可以 cd .. 进入到外面本应该不能被访问的文件夹,但是 chroot 需要 root 权限,因此在进入到用户编写的代码逻辑之前,我们需要更改进程权限,使得进程的当前用户/组转移到非 root 用户/组上,还比如存在一些如 openat 这样的系统调用可以绕过的问题,不过也都会通过一些细节处理来防护,这里就不多展开赘述。

2. 网络层面,其实不太好直接在 Sandbox 内进行处理,首先因为docker本身限制了iptables,在没有 k8s 环境的情况下,我们很难配置系统层级的网络策略,再者网络配置是一个极其复杂的工程,并非一点简单的策略就可以解决的,我们需要给用户提供可以自由配置的办法,同时,在k8s和docker-compose中,网络隔离策略的配置也是完全不同的,综上所述,我们最终的解决方案是docker-compose和k8s各做一套:

  • docker-compose 上,我们使用一个独立的 internal 模式的网络来作为 sandbox 的网络,再引入一个 proxy 容器连接外部网络,作为 sandbox 的代理容器,最终在proxy容器上配置代理规则,就可以实现我们提到的自由配置,网络大概如下图所示,Sandbox 位于 SSRF_PROXY_NET 中,这个网络是一个内部网络,无法访问外部,同时 proxy 器也位于这个网络中,同时 proxy 容器还处于 DEFAULT 网络中,那么就可以由 proxy 作为代理访问外部网络,也可以配置很灵活的网络代理规则,从而确保内网安全,不过在这里 Dify 本身也使用了 proxy 容器,这是因为如 HTTP 节点之类的功能也存在安全问题,因此统一通过 proxy 的代理规则进行配置。

  • k8s 上就很简单了,只需要配置 Exgress 即可实现网络隔离,不多赘述。

总结

综上,DifySandbox 被设计为了一个依赖 Linux 本身而不依赖某一具体语言的沙盒运行时,主要的任务是给 Dify 提供一个安全的代码执行环境,确保 Dify 可以运行用户侧的代码,提供更灵活的功能,在安全层面,我们同时做了系统、磁盘、文件系统、网络、权限等多个方面的隔离策略以确保 Dify 的安全性,也做了多层的隔离,避免使用特权。

但是目前而言还是存在诸多不足的,如 Python、Nodejs 的依赖很难处理,即使目前已经有了一些 Python 的依赖手段,但仍然还是存在诸多问题没有解决,还比如因为白名单策略,导致 Python、Nodejs 本身的一些正常行为被意外拦截等等,不过我们也会进一步优化 Sandbox,给到大家更好的体验。

今天,我们开放了 DifySandbox 的源码,这是我们一直以来对开源的态度,希望为 DifySandbox 增加更多的可能性,也希望为社区带来更多的价值,让大家都能参与到 Dify 的建设中来,并且在未来的计划中,Sandbox 还有许多可以想象的空间,如实现图片处理、实现更灵活的数据分析,实现生成图片、视频等,届时也欢迎社区的大家一起参与讨论和建设~


53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询

扫码登录
登录即表示您同意《53AI网站服务协议》
服务协议

欢迎您使用【53AI 官方网站】(以下简称“本网站”或“我们”)。本《会员服务协议》(以下简称“本协议”)是您(以下简称“会员”或“用户”)与【深圳市博思协创网络科技有限公司】之间关于注册、登录及使用本网站会员服务所订立的法律协议。

在您注册或登录前,请务必审慎阅读、充分理解各条款内容,特别是免除或限制责任的条款、知识产权条款、争议解决条款等。此类条款将以加粗形式提示您注意。 当您通过微信公众号授权、手机验证码验证或其他方式成功登录本网站时,即视为您已完全理解并同意接受本协议的全部内容。

一、 定义

本网站:指由【深圳市博思协创网络科技有限公司】运营的,域名为【53ai.com】的网站及相关移动端页面。

会员服务:指本网站向注册会员提供的知识库文章查阅、内容检索及其他相关增值服务。

知识库内容:指本网站发布的包括但不限于文字、图表、数据、研究报告、行业分析等数字化内容资源。

二、 账号注册与登录

登录方式:本网站支持以下登录方式,您可根据实际情况选择:

微信公众号授权登录:您同意将您的微信OpenID信息授权给本网站,用于创建或关联会员账号。

手机验证码登录:您需提供真实有效的手机号码,并通过短信验证码完成身份验证与登录/注册。

账号安全:您的账号仅限您本人使用,禁止赠与、借用、租用、转让或售卖。因您保管不善导致的账号被盗、密码泄露等损失,由您自行承担。

实名认证:根据相关法律法规要求,我们可能要求您在特定功能下完成实名认证。如您拒绝提供,可能无法使用部分或全部服务。

未成年人保护:若您未满18周岁,请在法定监护人的陪同下阅读本协议,并在征得监护人同意后使用本服务。

三、 服务内容与规范

知识库查阅权限:会员登录后,有权按照其会员等级对应的权限范围,在线浏览、检索本网站知识库中的相关文章及内容。

服务变更:我们有权根据业务发展需要,调整、变更或终止部分服务内容,并将以网站公告、公众号消息等方式提前通知。

禁止行为:您在使用服务时不得实施以下行为:

利用技术手段批量爬取、下载、转存知识库内容;

将知识库内容用于商业目的或未经授权地向第三方传播;

干扰本网站正常运行或侵犯其他用户合法权益;

发布违法违规信息或从事违反公序良俗的活动。

四、 知识产权声明

权利归属:本网站知识库中的排版设计、软件代码等内容的知识产权均归【公司全称】或原权利人所有,受《中华人民共和国著作权法》等法律保护。

有限许可:本网站授予会员一项非独占、不可转让、不可转授权的普通许可,仅限于个人学习、研究之目的在线查阅知识库内容。

侵权追责:未经书面许可,任何单位或个人不得以任何形式复制、转载、摘编、镜像、汇编或以其他方式使用上述内容。一经发现,我们保留追究其法律责任的权利。

五、 个人信息保护

我们重视对您个人信息的保护。关于我们如何收集、使用、存储和保护您的个人信息,请单独阅读 《隐私政策》。

您通过微信公众号授权或手机号验证所提供的信息,我们将严格按照《个人信息保护法》的规定处理,仅用于身份识别、服务提供及安全验证等必要用途。

您可以随时通过网站设置或联系客服行使查阅、更正、删除个人信息及撤回授权同意的权利。

六、 免责声明

内容准确性:知识库内容仅供参考,不构成专业建议。我们不对其完整性、准确性、时效性作任何明示或暗示的保证,您应自行判断并承担使用风险。

不可抗力:因自然灾害、政策法规变化、网络故障、第三方平台接口异常(如微信接口维护、运营商短信通道故障)等不可抗力导致的服务中断或延迟,我们不承担违约责任。

第三方链接:本网站可能包含指向第三方网站的链接,该等网站的内容和服务不受我们控制,请您自行甄别风险。

七、 违约责任

如您违反本协议约定,我们有权视情节采取警告、限制功能、暂停服务、注销账号等措施,并保留要求赔偿损失的权利。

如因您的违约行为导致我们遭受行政处罚、第三方索赔或商誉损失,您应承担全部赔偿责任(包括但不限于罚款、赔偿金、律师费、公证费等)。

八、 法律适用与争议解决

本协议的订立、执行和解释均适用中华人民共和国大陆地区法律。

因本协议产生的或与本协议有关的任何争议,双方应友好协商解决;协商不成的,任何一方均可向【公司所在地】有管辖权的人民法院提起诉讼。

九、 其他

本协议构成双方就本服务达成的完整协议,取代此前任何口头或书面约定。

本协议任一条款被认定为无效或不可执行的,不影响其他条款的效力。

我们对本协议享有最终解释权,并在法律允许的范围内保留随时修改的权利。修改后的协议一经公布即生效,继续使用服务即视为同意修订内容。


已查阅