understanding-tauri-ipc

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Tauri 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 done
Frontend (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
    fetch()
    API
  • 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:与浏览器的
    fetch()
    API 类似
  • 要求:参数和返回数据必须可序列化为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

工作原理

  1. Tauri's IPC handler receives a message from frontend
  2. Message routes to the Isolation application (sandboxed iframe)
  3. Isolation hook validates and potentially modifies the message
  4. Message encrypts using AES-GCM with runtime-generated keys
  5. Encrypted message returns to IPC handler
  6. 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
  1. Tauri的IPC处理器接收来自前端的消息
  2. 消息路由到隔离应用(沙箱化iframe)
  3. 隔离钩子验证并可能修改消息
  4. 使用运行时生成的密钥通过AES-GCM加密消息
  5. 加密后的消息返回给IPC处理器
  6. 加密消息传递到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.js
dist-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.js
dist-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

最佳实践

  1. Keep it simple: Minimize isolation application dependencies
  2. No bundlers: Skip ES Modules and complex build processes
  3. Validate inputs: Verify IPC calls match expected parameters
  4. Whitelist commands: Only allow known, safe commands
  5. Log suspicious activity: Monitor for potential attacks
  6. Apply to events: Validate events that trigger Rust code

  1. 保持简洁:最小化隔离应用的依赖
  2. 不使用打包工具:跳过ES模块和复杂构建流程
  3. 验证输入:确认IPC调用匹配预期参数
  4. 白名单命令:仅允许已知的安全命令
  5. 记录可疑活动:监控潜在攻击行为
  6. 应用到事件:验证触发Rust代码的事件

Pattern Comparison

模式对比

AspectBrownfieldIsolation
DefaultYesNo
ConfigurationNone requiredRequires isolation app
SecurityBasicEnhanced
ValidationCommand-level onlyAll IPC calls
EncryptionNoneAES-GCM
PerformanceFastestSlight overhead
ComplexitySimpleModerate
Best forTrusted code, prototypesProduction, sensitive apps
维度棕地模式隔离模式
是否默认
配置要求无需配置需要隔离应用
安全级别基础增强
验证范围仅命令级所有IPC调用
加密机制AES-GCM
性能最快轻微开销
复杂度简单中等
最佳适用可信代码、原型生产环境、敏感应用

Security Best Practices

安全最佳实践

For Both Patterns

两种模式通用

  1. Validate all inputs in Rust commands
    rust
    #[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())
    }
  2. Use typed arguments
    rust
    #[derive(serde::Deserialize)]
    struct CreateUserArgs {
        name: String,
        email: String,
    }
    
    #[tauri::command]
    fn create_user(args: CreateUserArgs) -> Result<(), String> {
        // Type-safe argument handling
        Ok(())
    }
  3. Limit exposed commands: Only expose necessary functionality
  4. Use capability-based permissions: Configure permissions in
    capabilities/
  1. 在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())
    }
  2. 使用类型化参数
    rust
    #[derive(serde::Deserialize)]
    struct CreateUserArgs {
        name: String,
        email: String,
    }
    
    #[tauri::command]
    fn create_user(args: CreateUserArgs) -> Result<(), String> {
        // 类型安全的参数处理
        Ok(())
    }
  3. 限制暴露的命令:仅暴露必要功能
  4. 使用基于能力的权限:在
    capabilities/
    目录中配置权限

For Isolation Pattern

隔离模式专属

  1. Keep isolation code minimal: Reduce attack surface
  2. Avoid external dependencies: No npm packages in isolation app
  3. Use strict validation: Whitelist over blacklist
  4. Test thoroughly: Ensure validation catches edge cases
  1. 保持隔离代码最小化:减少攻击面
  2. 避免外部依赖:隔离应用中不使用npm包
  3. 使用严格验证:优先白名单而非黑名单
  4. 全面测试:确保验证能覆盖边缘情况

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.
选择棕地模式的场景:
  • 构建内部工具
  • 快速原型开发
  • 前端代码完全可信
  • 安全要求较低
选择隔离模式的场景:
  • 构建面向公众的应用
  • 处理敏感用户数据
  • 使用大量第三方前端包
  • 安全为优先考虑项
  • 有合规要求
如有疑问,生产环境应用优先选择隔离模式