安全模型
沙箱隔离、权限声明与敏感操作确认机制
安全模型
Such 插件系统通过沙箱隔离 + 权限声明 + 敏感操作确认三层机制保障用户安全。
沙箱执行机制
插件代码不是直接运行在 Node.js 环境中,而是通过 Function 构造函数在受限作用域中执行:
new Function('window', 'suchmusic', code)(sandboxWindow, suchmusicAPI)这意味着插件代码中:
- 无法访问 Node.js 内置模块(
fs、child_process、path等) - 无法访问 Electron API(
ipcRenderer、shell等) - 无法访问 全局
window对象(被替换为受限的sandboxWindow) - 无法使用
require()或import(ESM/CJS 均不可用)
受限 window 对象
插件中可访问的 window 只包含:
| 属性 | 说明 |
|---|---|
window.source | 插件元数据容器,开发者向此赋值注册插件 |
window.notify(message, type?) | 向用户发送桌面通知 |
window.console | 被拦截的 console(输出转到宿主日志) |
// ✅ 可用
window.notify('操作完成', 'success')
console.log('输出到宿主日志')
// ❌ 不可用
// require('fs')
// process.cwd()
// document.querySelector()敏感操作确认机制
涉及本地系统访问的 API 属于敏感操作,每次调用前都需要用户确认。
哪些 API 是敏感操作?
| API | 原因 |
|---|---|
execProgram | 可执行任意本地程序 |
execTerminal | 可执行任意终端命令 |
fileOp | 可读写/删除任意本地文件 |
downloadFile | 可从网络下载文件到本地 |
writeMeta | 可修改音乐文件 |
确认流程
插件调用敏感 API
→ 宿主拦截,暂停执行
→ 向渲染进程发送确认请求
→ 展示确认弹窗(操作类型、详情)
→ 用户选择:确认 / 拒绝
→ 确认:继续执行 API
→ 拒绝:抛出 Error("用户拒绝了敏感操作: xxx")批量合并 (防抖)
如果插件在短时间内连续调用多个敏感操作(如批量下载文件),宿主会通过 100ms 防抖 将多个操作合并为一次批量确认:
100ms 内调用了 5 个 fileOp('copy', ...)
→ 宿主将 5 个操作合并为 1 个批量确认窗口
→ 用户可逐条确认/拒绝,或一键全部确认/拒绝"本次会话不再询问"
确认弹窗中提供"本次会话不再询问"选项。勾选后:
- 该插件的同类操作在当前运行会话中不再弹出确认
- 重启 Such 后恢复确认(安全设计)
- 只跳过相同操作类型(如
fileOp),不影响其他类型
超时机制
确认弹窗有 30 秒超时。超时后自动拒绝,返回权限错误。避免因用户长时间不操作导致插件无限挂起。
歌单操作安全
歌单操作(createPlaylist、addToPlaylist 等)虽然不是敏感操作,但通过 IPC 请求-响应模式实现,有 15 秒超时。这种方式确保歌单修改在渲染进程侧执行,主进程只做转发。
开发者注意事项
- 不要做危险操作:即使通过敏感操作确认,插件也不应执行
rm -rf、修改系统文件等破坏性操作 - 告知用户操作目的:敏感操作的
detail会自动显示在确认弹窗中,确保参数信息清晰可读 - 不要尝试绕过沙箱:
Function构造函数的参数已固定,无法通过arguments.callee等方式逃逸 - 异步操作也要确认:每个敏感 API 调用独立确认,批量调用会被合并但不会跳过