Safe Haven 中文文档 下载 App

Safe Haven 扫描器三服务架构,全跑在 Linux VPS 上

为什么要分成三个服务

Safe Haven 的后端按职责分成三大组件:Routing Backend(Cloudflare Workers)、Storage Layer(S3 存储桶)、Scanner Service(独立扫描引擎)。Scanner Service 本身又进一步拆成三个独立的 systemd 后台服务,全部跑在一台 Linux VPS 上。

拆分的理由是隔离性——一个服务崩溃不影响其他,更新定义库不需要重启扫描引擎,互相之间通过 HTTP API 或本地 SQLite 文件通信,完全解耦。

三个服务一览

服务名端口职责运行频率
safehaven-scanner8080主扫描引擎常驻后台,轮询任务队列
safehaven-hash8081本地威胁数据库常驻后台,每 2 小时更新
safehaven-defs无定义更新工具每天定时跑一次

safehaven-scanner(端口 8080)

这是扫描管线的主引擎。它的核心流程:

1. 向 Routing Backend 查询 pending_scan 状态的任务队列
2. 从 staging 目录下载 APK(presigned URL,5 分钟过期)
3. 调用 safehaven-hash 做本地哈希比对
4. 可选:加载 VX-TITANIUM 引擎做字节结构分析和 ML 分类
5. 从 APK manifest 提取版本号、包名、签名密钥
6. 比对签名哈希(Signing-Key Pinning)
7. 扫描结果回传到 Routing Backend

扫描器把文件标记为 scanning 状态,防止多个 worker 实例重复处理同一个任务。扫描完成后回传结果,Routing Backend 根据结果把状态推进到 live、rejected 或 pending_review。

扫描器服务有公开 API(Scanner Secret 权限),Routing Backend 用共享密钥调用它来提交扫描任务和查询结果。

safehaven-hash(端口 8081)

这是一个独立的本地威胁数据库服务。它维护一个隔离的 SQLite 文件,存放:

为什么要单独一个服务?因为 Safe Haven 的一个核心设计目标是客户端环境隐私——扫描器处理 APK 时,不会把文件哈希泄漏给外部第三方 API。所有恶意检查都在本地 SQLite 里完成,彻底切断和外部威胁情报 API 的数据流出。

safehaven-hash 的数据更新由 safehaven-defs 负责。

safehaven-defs(无端口)

这是一个定时工具(systemd timer,每 24 小时跑一次):

  1. 从公开威胁情报源拉取最新的恶意哈希、签名模式、VX-TITANIUM ML 定义包
  2. 更新 safehaven-hash 的 SQLite 数据库
  3. 如果 .so 引擎库有更新,通知 safehaven-scanner 平滑重启(不中断正在跑的扫描任务)

更新后不需要手动干预——scanner 服务在下次启动或热加载时自动读取新定义。

扫描结果怎么回到客户端

完整的数据链:

APK → staging → scanner 处理 → 回传扫描结果(签名哈希、VTTI 摘要、是否检出)
→ Routing Backend 更新应用条目 → 写入 index.json → S3 存储桶
→ 客户端下次同步时拉到更新后的索引 → 详情页展示新的扫描结果

安全隔离设计

三个服务的隔离设计除了职责解耦,还有一层安全考虑:

这样即使 VPS 的 8080 端口被扫到,没有 Secret token 也调不动扫描管线。

为什么用 systemd

Safe Haven 选择 systemd 而不是 Docker 或 supervisor:

扫描是安全的吗

Safe Haven 扫描管线的安全设计亮点: