开源下载管理器 FluxDown 插件系统的安全设计复盘。项目地址:https://github.com/zerx-lab/FluxDown ,官网:https://fluxdown.zerx.dev (AGPL,免费无广告)。利益相关:作者本人。

需求:让下载器「什么都能下」

下载器的死穴不是速度,是「链接它不认识」。与其作者逐站适配,不如学 yt-dlp 把站点适配交给社区:插件 = manifest.json + 一个 JS 文件,核心是 resolve(ctx) 函数——任务启动前把 URL 交给插件换取真实直链,每次启动/续传重解析,直链过期问题天然消失。

但「在宿主进程里执行第三方 JS」是个安全雷区。这篇文章记录我踩过的设计决策。

1. 运行时选型:为什么是 QuickJS(rquickjs)而不是 V8/deno_core

  • 引擎是纯 Rust crate,要嵌到桌面 App、headless server、CLI 三个宿主里,V8 的体积与构建复杂度不可接受;
  • QuickJS 有原生的 memory limit 与 interrupt handler,资源熔断是引擎级能力;
  • 通过 trait 隔离运行时抽象,跨 JS 边界的结构体禁止出现 rquickjs 类型——未来可无痛换 deno_core。

一个坑:rquickjs 叠加 rust-alloc feature 会让 set_memory_limit 静默失效,排查了很久。

2. 三重资源兜底 + 熔断

每次调用新建 AsyncRuntime + AsyncContext(无状态、无跨调用污染),同时挂三道保险:内存上限(QuickJS memory_limit)、CPU 中断(interrupt handler 按 ns 预算切)、墙钟超时(宿主侧 tokio timeout 外层兜底)。连续 3 次 Timeout/MemoryLimit 触发熔断,插件自动禁用并标记原因,用户可见。

3. 网络出口:SSRF 守卫的三条腿

插件能发 HTTP 请求,就必须防它探内网。单一判定函数 is_globally_routable_unicast 复用到三个位置:

  1. 字面量 IP 前置校验:URL 里直接写内网 IP 直接拒;
  2. 自定义 DNS Resolver:域名解析结果逐个校验,防 DNS rebinding;
  3. redirect Policy::custom:重定向逐跳复查,防「先跳外网再 302 回内网」。

4. 能力面:权限声明 + 不注入即不存在

插件想调 ffmpeg / yt-dlp,必须在 manifest 写 permissions。没声明的插件,flux.ffmpeg 这个对象根本不会注入到 JS 全局——不是运行时报错,是 undefined。安装时权限清单对用户可见。

5. 子进程牢笼:near-raw argv + 参数校验器

ffmpeg/yt-dlp 走「近乎全量 CLI 透传」而不是逐能力封装 API,但 argv 逐 token 过校验器:

  • ffmpeg:拒 URL scheme、协议前缀(file:/concat:)、绝对路径/盘符/…,文件引用一律相对 cwd=下载目录牢笼;除法(30000/1001)、流选择器(0:a)、滤镜(scale=1280:720)等合法语法放行;
  • yt-dlp:本职是抓站所以放行 URL,但封 13 个危险开关(–exec、–config-location、–cookies-from-browser 等),自动前置 --ignore-config,cwd 是插件独立 scratch 目录;
  • 两者都是 off-actor 子进程 + kill_on_drop + 全局并发 2 + 超时上限。

托管的 ffmpeg 不在 PATH,宿主经 --ffmpeg-location 注入可信路径——插件自带的同名参数仍在黑名单。

6. 失败语义:插件永远不能拖垮下载

  • resolve 失败 → fail-closed,任务正常报错,绝不把网页 HTML 当视频落盘;
  • 通知钩子(onStart/onDone/onError)全部 fire-and-forget:超时、报错只记日志;
  • resolve 在 off-actor 线程跑,宿主单线程 actor 永不阻塞。

7. 去中心化插件市场

索引 = Git 仓库(任何人 fork 自建源),插件包内容寻址(sha256 钉住 zip 全文),多镜像 failover,per-index sequence 防回滚。v1 没有作者签名(schema 已预留字段),完整性基座 = 内容寻址 + TLS + Git Merkle DAG。

结语

完整实现都在仓库 native/engine/src/plugin/ 目录,欢迎 review 拍砖:

  • GitHub:https://github.com/zerx-lab/FluxDown
  • 官网 & 插件开发文档:https://fluxdown.zerx.dev

如果你有想适配的站点,评论区聊。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐