在 Tauri 中,敏感接口(如文件读写、Shell 命令、系统托盘操作等)并非默认对前端开放,而是通过 配置驱动的权限模型 进行严格管控。这意味着,即使前端代码中出现恶意调用,真正能够触及系统能力的通道也必须经过两道“关卡”:编译期的静态权限声明和运行时的动态参数校验。
1. 权限白名单:默认全拒,按需开启
Tauri 将所有与系统交互的能力都归类放在 tauri.conf.json 的 allowlist 配置中。所有选项的默认值均为 false,只有在开发者在配置中显式开启后,对应的 API 才会在前端可见。例如,若未启用 fs 模块,前端调用 window.TAURI.fs.readFile 将直接抛出错误,根本不存在绕过可能。
// tauri.conf.json
{
"tauri": {
"allowlist": {
"fs": {
"all": false,
"readFile": true,
"scope": ["$APPDATA/*"]
},
"shell": {
"all": false,
"open": true
}
}
}
}
这种配置在编译时就被固化进应用,不可能在运行时被前端修改,确保 “没有声明=没有能力” 的强制约束。
2. IPC 命令注册:拒绝隐形入口
Rust 后端只有加了 #[tauri::command] 宏的函数才能被前端调用,且必须显式注册到 Tauri 应用的命令列表中。前端无法调用任何未注册的函数,也不存在类似 Electron 中 require(‘child_process’) 的万能入口。
// 只有这个函数可以被前端调用
#[tauri::command]
fn my_sensitive_operation(file_path: String) -> Result<String, String> {
// 业务逻辑
}
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![my_sensitive_operation])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
前端调用时通过 invoke('my_sensitive_operation', { filePath: '/path/to/file' }),Tauri 会根据函数签名自动反序列化参数,并校验类型。如果参数类型不符,调用将直接失败,不会执行到实际业务逻辑。
3. 动态作用域限制:缩小授权范围
即使某个功能被开启(例如文件读取),也还可以通过 scope(作用域) 进一步限制可访问的路径或资源。例如,上面的配置中 scope: ["$APPDATA/*"] 意味着前端 readFile 只能读取用户应用数据目录下的文件,尝试访问其他路径(如系统目录)会被底层拦截。
对于更复杂的场景(如网络请求),同样可以通过 scope 限制允许的 URL 模式,防止前端滥用网络权限与任意服务器通信。
4. 真实安全效果:XSS 也很难突破
假设前端出现跨站脚本攻击(XSS),攻击者最多能调用已注册的命令,且这些命令的权限和参数范围都已配置固定。例如,如果未开启 shell.execute,即使攻击者控制了整个页面也无法执行系统命令。这种 “能力最小化” 的架构极大降低了漏洞的破坏力。
5. 开发者实践建议
- 在
allowlist中只开启应用真正需要的 API 子集,不要图方便直接设置all: true。 - 对于自定义的 Rust 命令,务必在函数内部进行二次鉴权(如验证操作是否属于当前用户会话),不要完全依赖前端传入的所有参数。
- 定期审查
allowlist配置,随着功能迭代移除不再需要的权限。 - 如果需要动态调整权限,考虑在 Rust 后端实现基于用户身份或上下文的状态机,而不是盲目信任前端。
通过这种 “配置声明 + 命令注册 + 作用域拦截” 的多层限制,Tauri 将敏感接口的管理从“建议”变成了“强制”,让安全成为一种无需时刻警惕的默认状态。