understanding-tauri-ipc
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTauri Inter-Process Communication (IPC)
Tauri 进程间通信(IPC)
This skill covers Tauri's IPC system, including the brownfield and isolation patterns for secure communication between frontend and backend processes.
本技能介绍Tauri的IPC系统,包括用于前端与后端进程之间安全通信的棕地(brownfield)和隔离(isolation)模式。
Overview
概述
Tauri implements Inter-Process Communication using Asynchronous Message Passing. This enables isolated processes to exchange serialized requests and responses securely.
Why Message Passing?
- Safer than shared memory or direct function access
- Recipients can reject or discard malicious requests
- Tauri Core validates all requests before execution
- Prevents unauthorized function invocation
Tauri 采用异步消息传递实现进程间通信。这使得隔离的进程能够安全地交换序列化的请求和响应。
为什么选择消息传递?
- 比共享内存或直接函数访问更安全
- 接收方可以拒绝或丢弃恶意请求
- Tauri Core会在执行前验证所有请求
- 防止未授权的函数调用
IPC Primitives
IPC 基础组件
Tauri provides two IPC primitives:
Tauri 提供两种IPC基础组件:
Events
事件
- Direction: Bidirectional (Frontend <-> Tauri Core)
- Type: Fire-and-forget, one-way messaging
- Best for: Lifecycle events, state changes, notifications
Rust (emit to frontend):
rust
use tauri::{AppHandle, Emitter};
fn emit_event(app: &AppHandle) {
app.emit("backend-event", "payload data").unwrap();
}Frontend (listen):
typescript
import { listen } from '@tauri-apps/api/event';
const unlisten = await listen('backend-event', (event) => {
console.log('Received:', event.payload);
});
// Call unlisten() when doneFrontend (emit to backend):
typescript
import { emit } from '@tauri-apps/api/event';
await emit('frontend-event', { data: 'value' });- 通信方向:双向(前端 <-> Tauri Core)
- 类型:即发即弃的单向消息传递
- 最佳适用场景:生命周期事件、状态变更、通知
Rust(向前端发送事件):
rust
use tauri::{AppHandle, Emitter};
fn emit_event(app: &AppHandle) {
app.emit("backend-event", "payload data").unwrap();
}前端(监听事件):
typescript
import { listen } from '@tauri-apps/api/event';
const unlisten = await listen('backend-event', (event) => {
console.log('Received:', event.payload);
});
// 使用完成后调用 unlisten()前端(向后端发送事件):
typescript
import { emit } from '@tauri-apps/api/event';
await emit('frontend-event', { data: 'value' });Commands
命令
- Direction: Frontend -> Rust backend
- Protocol: JSON-RPC-based abstraction
- API: Similar to browser's API
fetch() - Requirement: Arguments and return data must be JSON-serializable
Rust command definition:
rust
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}Frontend invocation:
typescript
import { invoke } from '@tauri-apps/api/core';
const greeting = await invoke('greet', { name: 'World' });
console.log(greeting); // "Hello, World!"Async command with Result:
rust
#[tauri::command]
async fn read_file(path: String) -> Result<String, String> {
std::fs::read_to_string(&path)
.map_err(|e| e.to_string())
}- 通信方向:前端 -> Rust 后端
- 协议:基于JSON-RPC的抽象
- API:与浏览器的 API 类似
fetch() - 要求:参数和返回数据必须可序列化为JSON
Rust 命令定义:
rust
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}前端调用命令:
typescript
import { invoke } from '@tauri-apps/api/core';
const greeting = await invoke('greet', { name: 'World' });
console.log(greeting); // "Hello, World!"带Result的异步命令:
rust
#[tauri::command]
async fn read_file(path: String) -> Result<String, String> {
std::fs::read_to_string(&path)
.map_err(|e| e.to_string())
}IPC Patterns
IPC 模式
Tauri provides two IPC security patterns: Brownfield (default) and Isolation.
Tauri 提供两种IPC安全模式:棕地(Brownfield,默认)和隔离(Isolation)。
Brownfield Pattern
棕地模式
What It Is
模式说明
The brownfield pattern is Tauri's default IPC approach. It prioritizes compatibility with existing web frontend projects by requiring minimal modifications.
棕地模式是Tauri的默认IPC方案。它通过要求最少修改,优先保障与现有Web前端项目的兼容性。
When to Use
适用场景
- Migrating existing web applications to desktop
- Rapid prototyping and development
- Applications with trusted frontend code
- Simple applications with limited IPC surface
- 将现有Web应用迁移到桌面端
- 快速原型开发
- 前端代码可信的应用
- IPC交互面有限的简单应用
Why Use It
选择理由
- Zero configuration required
- Minimal changes to existing web code
- Direct access to Tauri APIs
- Fastest development path
- 无需任何配置
- 对现有Web代码修改极小
- 可直接访问Tauri API
- 开发路径最快捷
Configuration
配置方式
Brownfield is the default. Explicit configuration is optional:
json
{
"app": {
"security": {
"pattern": {
"use": "brownfield"
}
}
}
}Note: There are no additional configuration options for brownfield.
棕地模式是默认方案,显式配置为可选:
json
{
"app": {
"security": {
"pattern": {
"use": "brownfield"
}
}
}
}注意: 棕地模式没有额外的配置选项。
Code Example
代码示例
Rust backend:
rust
#[tauri::command]
fn process_data(input: String) -> Result<String, String> {
// Direct processing without isolation layer
Ok(format!("Processed: {}", input))
}Frontend:
typescript
import { invoke } from '@tauri-apps/api/core';
// Direct invocation - no isolation layer
const result = await invoke('process_data', { input: 'test' });Rust 后端:
rust
#[tauri::command]
fn process_data(input: String) -> Result<String, String> {
// 无隔离层的直接处理
Ok(format!("Processed: {}", input))
}前端:
typescript
import { invoke } from '@tauri-apps/api/core';
// 直接调用 - 无隔离层
const result = await invoke('process_data', { input: 'test' });Security Considerations
安全注意事项
- Frontend code has direct access to all exposed commands
- No additional validation layer between frontend and backend
- Supply chain attacks in frontend dependencies could invoke commands
- Rely on command-level validation in Rust
- 前端代码可直接访问所有暴露的命令
- 前端与后端之间无额外验证层
- 前端依赖中的供应链攻击可能会调用命令
- 依赖Rust中的命令级验证
Isolation Pattern
隔离模式
What It Is
模式说明
The isolation pattern intercepts and modifies all Tauri API messages from the frontend using JavaScript before they reach Tauri Core. A secure JavaScript application (the Isolation application) runs in a sandboxed iframe to validate and encrypt all IPC communications.
隔离模式会在前端发送的所有Tauri API消息到达Tauri Core之前,使用JavaScript拦截并修改这些消息。一个安全的JavaScript应用(隔离应用)运行在沙箱化的iframe中,用于验证和加密所有IPC通信。
When to Use
适用场景
- Applications with many frontend dependencies
- High-security requirements
- Handling sensitive data or operations
- Public-facing applications
- When supply chain attacks are a concern
- 包含大量前端依赖的应用
- 高安全要求的应用
- 处理敏感数据或操作的应用
- 面向公众的应用
- 担忧供应链攻击的场景
Why Use It
选择理由
Protection against Development Threats:
- Validates all IPC calls before execution
- Catches malicious or unwanted frontend calls
- Mitigates supply chain attack risks
- Provides a checkpoint for all communications
Tauri recommends using isolation whenever feasible.
针对开发阶段威胁的防护:
- 执行前验证所有IPC调用
- 捕获恶意或非预期的前端调用
- 降低供应链攻击风险
- 为所有通信提供检查点
Tauri 建议尽可能使用隔离模式。
How It Works
工作原理
- Tauri's IPC handler receives a message from frontend
- Message routes to the Isolation application (sandboxed iframe)
- Isolation hook validates and potentially modifies the message
- Message encrypts using AES-GCM with runtime-generated keys
- Encrypted message returns to IPC handler
- Encrypted message passes to Tauri Core for decryption and execution
Key Security Features:
- New encryption keys generated on each application launch
- Sandboxed iframe prevents isolation code manipulation
- All IPC calls validated, including event-based APIs
- Tauri的IPC处理器接收来自前端的消息
- 消息路由到隔离应用(沙箱化iframe)
- 隔离钩子验证并可能修改消息
- 使用运行时生成的密钥通过AES-GCM加密消息
- 加密后的消息返回给IPC处理器
- 加密消息传递到Tauri Core进行解密和执行
核心安全特性:
- 每次应用启动时生成新的加密密钥
- 沙箱化iframe防止隔离代码被篡改
- 验证所有IPC调用,包括基于事件的API
Configuration
配置方式
tauri.conf.json:
json
{
"app": {
"security": {
"pattern": {
"use": "isolation",
"options": {
"dir": "../dist-isolation"
}
}
}
}
}tauri.conf.json:
json
{
"app": {
"security": {
"pattern": {
"use": "isolation",
"options": {
"dir": "../dist-isolation"
}
}
}
}
}Code Example
代码示例
Directory structure:
project/
src/ # Main frontend
src-tauri/ # Rust backend
dist-isolation/
index.html
index.jsdist-isolation/index.html:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Isolation Secure Script</title>
</head>
<body>
<script src="index.js"></script>
</body>
</html>dist-isolation/index.js:
javascript
window.__TAURI_ISOLATION_HOOK__ = (payload) => {
// Log all IPC calls for debugging
console.log('IPC call intercepted:', payload);
// Return payload unchanged (passthrough)
return payload;
};Validation example (index.js):
javascript
window.__TAURI_ISOLATION_HOOK__ = (payload) => {
// Validate command calls
if (payload.cmd === 'invoke') {
const { __tauriModule, message } = payload;
// Block unauthorized file system access
if (message.cmd === 'readFile') {
const path = message.path;
if (!path.startsWith('/allowed/directory/')) {
console.error('Blocked unauthorized file access:', path);
return null; // Block the request
}
}
// Validate specific commands
if (message.cmd === 'deleteItem') {
if (!confirm('Are you sure you want to delete this item?')) {
return null; // User cancelled
}
}
}
return payload;
};Comprehensive validation example:
javascript
const ALLOWED_COMMANDS = ['greet', 'read_config', 'save_settings'];
const BLOCKED_PATHS = ['/etc/', '/usr/', '/System/'];
window.__TAURI_ISOLATION_HOOK__ = (payload) => {
// Validate invoke commands
if (payload.cmd === 'invoke') {
const commandName = payload.message?.cmd;
// Whitelist approach
if (!ALLOWED_COMMANDS.includes(commandName)) {
console.warn('Blocked unknown command:', commandName);
return null;
}
// Validate path arguments
const args = payload.message?.args || {};
if (args.path) {
for (const blocked of BLOCKED_PATHS) {
if (args.path.startsWith(blocked)) {
console.error('Blocked access to protected path:', args.path);
return null;
}
}
}
}
// Validate event emissions
if (payload.cmd === 'emit') {
const eventName = payload.event;
// Add event validation as needed
}
return payload;
};目录结构:
project/
src/ # 主前端代码
src-tauri/ # Rust 后端代码
dist-isolation/
index.html
index.jsdist-isolation/index.html:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Isolation Secure Script</title>
</head>
<body>
<script src="index.js"></script>
</body>
</html>dist-isolation/index.js:
javascript
window.__TAURI_ISOLATION_HOOK__ = (payload) => {
// 记录所有IPC调用用于调试
console.log('IPC call intercepted:', payload);
// 保持payload不变(直接传递)
return payload;
};验证示例(index.js):
javascript
window.__TAURI_ISOLATION_HOOK__ = (payload) => {
// 验证命令调用
if (payload.cmd === 'invoke') {
const { __tauriModule, message } = payload;
// 阻止未授权的文件系统访问
if (message.cmd === 'readFile') {
const path = message.path;
if (!path.startsWith('/allowed/directory/')) {
console.error('Blocked unauthorized file access:', path);
return null; // 阻止请求
}
}
// 验证特定命令
if (message.cmd === 'deleteItem') {
if (!confirm('Are you sure you want to delete this item?')) {
return null; // 用户取消
}
}
}
return payload;
};全面验证示例:
javascript
const ALLOWED_COMMANDS = ['greet', 'read_config', 'save_settings'];
const BLOCKED_PATHS = ['/etc/', '/usr/', '/System/'];
window.__TAURI_ISOLATION_HOOK__ = (payload) => {
// 验证invoke命令
if (payload.cmd === 'invoke') {
const commandName = payload.message?.cmd;
// 白名单机制
if (!ALLOWED_COMMANDS.includes(commandName)) {
console.warn('Blocked unknown command:', commandName);
return null;
}
// 验证路径参数
const args = payload.message?.args || {};
if (args.path) {
for (const blocked of BLOCKED_PATHS) {
if (args.path.startsWith(blocked)) {
console.error('Blocked access to protected path:', args.path);
return null;
}
}
}
}
// 验证事件发送
if (payload.cmd === 'emit') {
const eventName = payload.event;
// 根据需要添加事件验证
}
return payload;
};Performance Considerations
性能考量
- AES-GCM encryption overhead is minimal for most applications
- Comparable to TLS encryption used in HTTPS
- Key generation requires system entropy (handled seamlessly on modern systems)
- Performance-sensitive applications may notice slight impact
- AES-GCM加密开销对大多数应用来说极小
- 与HTTPS使用的TLS加密性能相当
- 密钥生成需要系统熵(现代系统可无缝处理)
- 对性能敏感的应用可能会察觉到轻微影响
Limitations
限制
- ES Modules do not load in sandboxed iframes on Windows
- Scripts must be inlined during build time
- External files must be embedded rather than referenced
- Avoid bundlers for the isolation application
- Windows系统中,沙箱化iframe无法加载ES模块
- 构建时必须内联脚本
- 外部文件必须嵌入而非引用
- 隔离应用应避免使用打包工具
Best Practices
最佳实践
- Keep it simple: Minimize isolation application dependencies
- No bundlers: Skip ES Modules and complex build processes
- Validate inputs: Verify IPC calls match expected parameters
- Whitelist commands: Only allow known, safe commands
- Log suspicious activity: Monitor for potential attacks
- Apply to events: Validate events that trigger Rust code
- 保持简洁:最小化隔离应用的依赖
- 不使用打包工具:跳过ES模块和复杂构建流程
- 验证输入:确认IPC调用匹配预期参数
- 白名单命令:仅允许已知的安全命令
- 记录可疑活动:监控潜在攻击行为
- 应用到事件:验证触发Rust代码的事件
Pattern Comparison
模式对比
| Aspect | Brownfield | Isolation |
|---|---|---|
| Default | Yes | No |
| Configuration | None required | Requires isolation app |
| Security | Basic | Enhanced |
| Validation | Command-level only | All IPC calls |
| Encryption | None | AES-GCM |
| Performance | Fastest | Slight overhead |
| Complexity | Simple | Moderate |
| Best for | Trusted code, prototypes | Production, sensitive apps |
| 维度 | 棕地模式 | 隔离模式 |
|---|---|---|
| 是否默认 | 是 | 否 |
| 配置要求 | 无需配置 | 需要隔离应用 |
| 安全级别 | 基础 | 增强 |
| 验证范围 | 仅命令级 | 所有IPC调用 |
| 加密机制 | 无 | AES-GCM |
| 性能 | 最快 | 轻微开销 |
| 复杂度 | 简单 | 中等 |
| 最佳适用 | 可信代码、原型 | 生产环境、敏感应用 |
Security Best Practices
安全最佳实践
For Both Patterns
两种模式通用
-
Validate all inputs in Rust commandsrust
#[tauri::command] fn process_file(path: String) -> Result<String, String> { // Always validate paths if path.contains("..") || path.starts_with("/etc") { return Err("Invalid path".into()); } // Process file... Ok("Done".into()) } -
Use typed argumentsrust
#[derive(serde::Deserialize)] struct CreateUserArgs { name: String, email: String, } #[tauri::command] fn create_user(args: CreateUserArgs) -> Result<(), String> { // Type-safe argument handling Ok(()) } -
Limit exposed commands: Only expose necessary functionality
-
Use capability-based permissions: Configure permissions in
capabilities/
-
在Rust命令中验证所有输入rust
#[tauri::command] fn process_file(path: String) -> Result<String, String> { // 始终验证路径 if path.contains("..") || path.starts_with("/etc") { return Err("Invalid path".into()); } // 处理文件... Ok("Done".into()) } -
使用类型化参数rust
#[derive(serde::Deserialize)] struct CreateUserArgs { name: String, email: String, } #[tauri::command] fn create_user(args: CreateUserArgs) -> Result<(), String> { // 类型安全的参数处理 Ok(()) } -
限制暴露的命令:仅暴露必要功能
-
使用基于能力的权限:在目录中配置权限
capabilities/
For Isolation Pattern
隔离模式专属
- Keep isolation code minimal: Reduce attack surface
- Avoid external dependencies: No npm packages in isolation app
- Use strict validation: Whitelist over blacklist
- Test thoroughly: Ensure validation catches edge cases
- 保持隔离代码最小化:减少攻击面
- 避免外部依赖:隔离应用中不使用npm包
- 使用严格验证:优先白名单而非黑名单
- 全面测试:确保验证能覆盖边缘情况
Choosing a Pattern
模式选择建议
Use Brownfield when:
- Building internal tools
- Prototyping rapidly
- Frontend code is fully trusted
- Minimal security requirements
Use Isolation when:
- Building public applications
- Handling sensitive user data
- Using many third-party frontend packages
- Security is a priority
- Compliance requirements exist
When in doubt, prefer isolation for production applications.
选择棕地模式的场景:
- 构建内部工具
- 快速原型开发
- 前端代码完全可信
- 安全要求较低
选择隔离模式的场景:
- 构建面向公众的应用
- 处理敏感用户数据
- 使用大量第三方前端包
- 安全为优先考虑项
- 有合规要求
如有疑问,生产环境应用优先选择隔离模式。