安全架构 #
一、安全模型概述 #
1.1 安全设计原则 #
Tauri 的安全设计遵循以下原则:
| 原则 | 说明 |
|---|---|
| 最小权限 | 只授予必要的权限 |
| 深度防御 | 多层安全防护 |
| 安全默认 | 默认配置是安全的 |
| 隔离运行 | 前后端隔离 |
1.2 安全架构 #
text
┌─────────────────────────────────────────────────────────────┐
│ 安全架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 前端 (WebView) │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ 沙箱环境 │ │ │
│ │ │ - 无直接文件系统访问 │ │ │
│ │ │ - 无直接系统 API 访问 │ │ │
│ │ │ - 受 CSP 策略限制 │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ │ IPC(受控通道) │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 后端 (Rust) │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ 权限检查 │ │ │
│ │ │ - 命令白名单 │ │ │
│ │ │ - 权限验证 │ │ │
│ │ │ - 资源访问控制 │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
二、安全边界 #
2.1 进程隔离 #
text
┌─────────────────┐ IPC ┌─────────────────┐
│ WebView │◄────────────►│ Rust Core │
│ (沙箱) │ 受控通信 │ (权限控制) │
└─────────────────┘ └─────────────────┘
2.2 上下文隔离 #
typescript
// WebView 中无法直接访问 Node.js/Rust
// 必须通过 IPC 通道
// ❌ 不可能直接访问
// const fs = require('fs');
// ✅ 通过 IPC 调用
import { invoke } from '@tauri-apps/api/core';
const content = await invoke('read_file', { path: '/path/to/file' });
2.3 预加载脚本安全 #
javascript
// preload.js
const { contextBridge, ipcRenderer } = require('electron');
// 只暴露白名单内的 API
contextBridge.exposeInMainWorld('myAPI', {
readFile: (path) => ipcRenderer.invoke('read-file', path),
writeFile: (path, content) => ipcRenderer.invoke('write-file', path, content),
});
三、权限系统 #
3.1 权限配置 #
json
// src-tauri/capabilities/default.json
{
"$schema": "https://schema.tauri.app/config/2/capability",
"identifier": "default",
"description": "Default capabilities",
"windows": ["main"],
"permissions": [
"core:default",
"shell:allow-open",
"dialog:allow-open",
"fs:allow-read-text-file",
"fs:allow-write-text-file"
]
}
3.2 权限粒度 #
json
{
"permissions": [
"fs:default",
"fs:allow-read-text-file",
"fs:allow-write-text-file",
"fs:deny-read-dir"
]
}
3.3 条件权限 #
json
{
"permissions": [
{
"identifier": "fs:allow-read-text-file",
"allow": [
{ "path": "$APPDATA/**" },
{ "path": "$DOCUMENT/**" }
]
}
]
}
四、CSP 配置 #
4.1 内容安全策略 #
json
// tauri.conf.json
{
"app": {
"security": {
"csp": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'"
}
}
}
4.2 CSP 指令详解 #
text
default-src 'self' 默认只加载同源资源
script-src 'self' 脚本只从同源加载
style-src 'self' 'unsafe-inline' 样式允许内联
img-src 'self' data: https: 图片允许同源、data 和 https
font-src 'self' https://fonts.gstatic.com 字体允许指定源
connect-src 'self' https://api.example.com 连接允许指定源
4.3 严格 CSP 示例 #
json
{
"csp": "default-src 'self'; " +
"script-src 'self'; " +
"style-src 'self'; " +
"img-src 'self' data:; " +
"font-src 'self'; " +
"connect-src 'self'; " +
"frame-ancestors 'none'; " +
"form-action 'self'; " +
"base-uri 'self'"
}
五、常见威胁防护 #
5.1 XSS 防护 #
typescript
// 输入验证
function sanitizeInput(input: string): string {
return input
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
// 使用 DOM API 而非 innerHTML
element.textContent = userInput; // ✅ 安全
element.innerHTML = userInput; // ❌ 危险
5.2 命令注入防护 #
rust
// ❌ 危险:直接拼接用户输入
fn dangerous_command(user_input: &str) {
let output = Command::new("sh")
.arg("-c")
.arg(format!("echo {}", user_input))
.output();
}
// ✅ 安全:使用参数数组
fn safe_command(user_input: &str) {
let output = Command::new("echo")
.arg(user_input)
.output();
}
5.3 路径遍历防护 #
rust
use std::path::{Path, PathBuf};
fn safe_path(base: &Path, user_path: &str) -> Result<PathBuf, String> {
let full_path = base.join(user_path);
// 规范化路径
let canonical = full_path.canonicalize()
.map_err(|e| e.to_string())?;
// 检查是否在基础目录内
let base_canonical = base.canonicalize()
.map_err(|e| e.to_string())?;
if !canonical.starts_with(&base_canonical) {
return Err("Path traversal detected".to_string());
}
Ok(canonical)
}
5.4 敏感数据保护 #
rust
// 不记录敏感数据
#[tauri::command]
fn login(username: String, password: String) -> Result<User, String> {
// ❌ 不要记录密码
// println!("Login attempt: {} - {}", username, password);
// ✅ 只记录必要信息
println!("Login attempt for user: {}", username);
// 验证后立即清除
let result = verify_credentials(&username, &password);
Ok(result)
}
六、安全配置 #
6.1 禁用开发工具 #
json
// tauri.conf.json
{
"app": {
"security": {
"devtools": false
}
}
}
6.2 禁用远程内容 #
json
{
"security": {
"csp": "default-src 'self'",
"dangerousRemoteDomainIpcAccess": []
}
}
6.3 安全窗口配置 #
json
{
"windows": [{
"webPreferences": {
"nodeIntegration": false,
"contextIsolation": true,
"sandbox": true
}
}]
}
七、安全审计 #
7.1 依赖审计 #
bash
# Rust 依赖审计
cargo audit
# 前端依赖审计
npm audit
pnpm audit
7.2 代码审查清单 #
text
□ 所有用户输入都经过验证和清理
□ 没有硬编码的敏感信息
□ 使用参数化查询防止 SQL 注入
□ 文件路径经过验证
□ 权限配置遵循最小权限原则
□ CSP 配置严格
□ 没有禁用安全特性
八、最佳实践 #
8.1 安全开发流程 #
text
1. 设计阶段:识别安全需求
2. 开发阶段:遵循安全编码规范
3. 测试阶段:安全测试
4. 发布阶段:安全审计
5. 运维阶段:监控和更新
8.2 安全检查清单 #
markdown
## 输入验证
- [ ] 验证所有用户输入
- [ ] 使用白名单验证
- [ ] 限制输入长度
## 输出编码
- [ ] HTML 实体编码
- [ ] URL 编码
- [ ] JavaScript 编码
## 认证授权
- [ ] 强密码策略
- [ ] 会话管理
- [ ] 权限检查
## 数据保护
- [ ] 敏感数据加密
- [ ] 安全存储
- [ ] 传输加密
九、总结 #
9.1 核心要点 #
| 要点 | 说明 |
|---|---|
| 进程隔离 | 前后端隔离运行 |
| 权限控制 | 细粒度权限管理 |
| CSP | 内容安全策略 |
| 输入验证 | 防止注入攻击 |
| 数据保护 | 敏感数据加密 |
9.2 下一步 #
现在你已经了解了安全架构,接下来让我们学习 权限控制,深入了解 Tauri 的权限系统!
最后更新:2026-03-28