安全模型总览
本教程共 48 篇 · 第 39 篇 · 更新于 2026-08-09 · 约 8 分钟阅读
本节目标:读完你能理解 Tauri 2 的信任边界(trust boundary)、IPC 隔离层、WebView 沙箱机制,以及 2.x 默认全拒绝的权限模型为什么是 Tauri 安全的基石。
如果你从 Tauri 1.x 过来,安全是 2.x 变化最大的部分。1.x 时代前端默认能调所有命令,你得手动加 allowlist 去限制。2.x 翻了个个儿——默认全拒绝,你必须显式授权。这不是改个配置那么简单,整个权限体系都重新设计了。本章先讲安全模型的全局图景,后面两章再深入 CSP 和权限配置细节。
信任边界:前端 vs 后端
想象一栋办公楼。外面的访客(前端代码)能进大厅、能用会议室,但不能进财务室、不能碰服务器。员工(Rust 后端代码)哪里都能去。区分访客和员工能去哪里的那条线,就是信任边界。
Tauri 把应用代码分成两个信任等级:
- 后端(Rust 核心代码 + 插件):完全信任,能访问所有系统资源——文件系统、网络、硬件、进程管理,不受限制。
- 前端(WebView 里的 JS/HTML/CSS):不完全信任,被关在沙箱里,只能通过 IPC 层(进程间通信层)调用后端暴露的命令。
为什么前端不可信?因为前端代码可能来自远程加载、可能被 XSS 注入、可能被中间人篡改。如果前端能直接调系统 API,攻击者只要注入一段脚本就能控制用户电脑。信任边界就是防止这种「越权」的第一道防线。
IPC 层:唯一的桥梁
前端和后端之间不能直接通信,必须经过 IPC 层。你可以把它理解成办公楼的访客登记台——访客想办什么事,只能到登记台排队,由工作人员(后端命令)代办。
IPC 层做了三件事:
- 路由:前端调用
invoke("command_name"),IPC 层根据命令名找到对应的后端函数。 - 权限检查:在执行命令前,先检查当前窗口有没有权限调这个命令。没权限直接拒绝,命令函数根本不会被调用。
- 作用域注入:如果命令有 scope(作用域限制),比如「只能读
$APPDATA目录」,IPC 层会把 scope 信息传给命令,命令在执行时据此校验。
前端 JS → IPC 层(权限检查 + scope 注入) → Rust 命令函数
↑
capabilities 配置
这个设计意味着,即使攻击者在前端注入了恶意代码调 invoke("read_file"),IPC 层会发现当前窗口没有 fs:allow-read-file 权限,直接拦截,后端的文件读取函数根本不会执行。
Runtime Authority:运行时权限引擎
IPC 层做权限检查时,依据的是谁?答案是 Runtime Authority(运行时权限引擎)。它是 Tauri 核心里的一个模块,在应用启动时加载所有 capabilities 和 permissions 配置,运行时为每次 IPC 调用做权限裁决。
工作流程:
- 应用启动,Runtime Authority 读取
src-tauri/capabilities/目录下的所有配置文件。 - 前端发来一个
invoke("read_file")请求,附带当前窗口的 label。 - Runtime Authority 查找:这个窗口的 capabilities 里有没有
fs:allow-read-file权限? - 有权限 → 把 scope 传给命令函数,放行。没权限 → 拒绝请求,命令函数不执行。
整个过程在 Rust 端完成,前端完全无法干预或绕过。这是 Tauri 安全模型的执行核心。
WebView 沙箱:不打包浏览器
Tauri 还有一个安全设计上的取舍值得讲:它不打包 WebView,而是用操作系统自带的。
为什么这更安全?因为 WebView(Edge WebView2 / WKWebView / WebKitGTK)的安全补丁由操作系统和浏览器厂商维护。他们发现漏洞、修复漏洞、推送更新的速度,通常比应用开发者快得多。如果你打包了一个特定版本的 Chromium(Electron 的做法),某个安全漏洞被公开后,你得自己改代码、重新构建、发布更新、等用户安装——这个链路可能花几周。而系统 WebView 的安全更新走操作系统的自动更新通道,用户可能第二天就装上了。
当然这也有代价——不同平台的 WebView 行为有差异,兼容性需要测试。但从安全角度看,这个取舍是合理的。
NoteTauri 不打包 WebView 不代表它「不安全」,恰恰相反——它利用了系统 WebView 的快速安全更新机制来缩短漏洞暴露窗口。这和 Electron 把 Chromium 打进安装包是两种不同的策略,各有取舍。
默认最小权限原则
这是 Tauri 2 安全模型最核心的一条原则,也是和 1.x 最大的区别。
打个比方:1.x 像给你的应用发了一张万能门禁卡,哪里都能进,你再自己决定哪些门要锁。2.x 给你一张空卡,哪扇门都进不去,你需要哪间就给哪间单独授权。
具体表现:
- 所有插件命令默认拒绝:安装了
plugin-fs不代表前端能读文件,必须在 capabilities 里加fs:allow-read-file之类的权限。 - scope 默认为空:即使授权了读文件,默认也不限定能读哪些路径。你需要用 scope 把可访问路径锁在具体目录,否则前端能读整个硬盘。
- 自定义命令默认允许:用
#[tauri::command]定义自己的命令时,默认是允许的。但你可以在 capabilities 中通过权限配置来限制哪些窗口能调用特定命令。
WarningTauri 1.x 的
allowlist机制和 2.x 的capabilities机制不是简单换了个名字。1.x 的 allowlist 是「允许列表」,默认拒绝;2.x 的 capabilities 是一套更细粒度的权限系统,支持 scope、permission set、按窗口/平台区分。迁移时不能简单对照名称替换,需要重新理解整个模型。
安全边界能防什么、不能防什么
了解边界很重要,既要知道它能保护你什么,也要知道它的局限。
能防的:
- 前端被 XSS 攻击后调用危险命令(没有权限就被拦)
- 意外暴露敏感系统接口(默认不授权就不会暴露)
- 前端到后端的权限提升(IPC 层做检查,Rust 端不受前端信任影响)
不能防的:
- 你自己写了不安全的 Rust 代码(Rust 端完全信任,能力越大责任越大)
- 配置太宽松(把所有权限都开了,等于没防)
- 供应链攻击(依赖的 npm/cargo 包被投毒)
- 系统 WebView 的零日漏洞(只能靠及时更新系统补丁)
Tip安全是一个木桶效应——最短的那块板决定整体水位。Tauri 帮你把前端到后端这块板做厚了,但你的 Rust 代码安全、依赖安全、构建安全同样是板子的一部分,不能忽视。
小结
Tauri 2 的安全模型建立在三个核心概念上:信任边界把前端(不可信)和后端(可信)隔开;IPC 层是两者间唯一的通信桥梁,每次调用都经过权限检查;Runtime Authority 是执行权限检查的运行时引擎,依据 capabilities 配置做放行或拒绝。Tauri 不打包 WebView 而是用系统自带的,利用操作系统的安全更新机制缩短漏洞暴露窗口。最关键的变化是默认最小权限原则——2.x 默认全拒绝,你必须显式授权每个命令和 scope。这套机制能防前端越权调用,但防不了不安全的 Rust 代码和过宽的配置——安全最终是你的责任。