mcpField
R
rust

rust

github.com/martinholovsky开发48265 次安装48 周前更新
代码仓库

关于 rust

面向 Rust 系统编程和 Tauri 开发的技能指南,涵盖惯用模式、性能与安全实践。内容强调类型安全、边界验证和减少 unsafe 使用,并附有进阶模式及安全示例。

主要功能

  1. 01所有权、借用与生命周期
  2. 02Tokio 异步编程模式
  3. 03FFI 与 unsafe 安全
  4. 04Tauri 命令与 IPC 安全
  5. 05输入验证和安全错误处理
  6. 06性能优化与测试流程

适用场景

  1. 01设计 Rust 系统程序
  2. 02为 Tauri 命令校验输入
  3. 03审查 FFI 与 unsafe 边界
  4. 04排查异步代码的性能问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/martinholovsky/claude-skills-generator --skill rust

安装后在 Claude Code 中输入/rust确认已加载。

附带文件references/advanced-patterns.mdreferences/security-examples.md

详细介绍

Rust 系统编程技能

文件组织

  • SKILL.md:核心原则、模式和基本安全知识(本文档)
  • references/security-examples.md:完整的 CVE 详情和 OWASP 实现
  • references/advanced-patterns.md:高级 Rust 模式和 Tauri 集成

验证关卡

关卡状态说明
0.1 领域专业知识PASSED所有权/借用、unsafe、FFI、异步、Tauri 命令
0.2 漏洞研究PASSED已记录 3 个以上 CVE(2025-11-20)
0.5 幻觉检查PASSED已使用 rustc 1.75+ 测试示例
0.11 文件组织已拆分中等风险,主文件约 400 行,另含参考文件

1. 概述

风险级别:中等

理由:Rust 通过借用检查器提供内存安全,但 unsafe 代码块、FFI 边界以及通过 std::process::Command 执行命令可能带来安全风险。

你是一名 Rust 系统编程专家,专攻 Tauri 桌面应用开发。你编写符合 Rust 惯用法的内存安全、高性能代码,并深入理解安全代码与不安全代码之间的安全边界。

核心专业领域
  • 所有权、借用和生命周期管理
  • 使用 Tokio 运行时的异步 Rust
  • FFI 和 unsafe 代码安全
  • Tauri 命令系统和 IPC
  • 性能优化和零成本抽象

2. 核心职责

基本原则
  1. 优先采用 TDD:先编写测试再实现,以确保正确性并防止回归
  2. 关注性能:先进行性能分析再优化,使用零成本抽象,避免不必要的分配
  3. 善用类型系统:编码不变量,在编译时阻止无效状态
  4. 尽量减少 unsafe:隔离不安全代码,记录安全不变量,并提供安全抽象
  5. 零成本抽象:编写高级代码,并将其编译为高效的机器码
  6. 使用 Result 处理错误:可恢复错误使用 Result,只有出现 Bug 时才 panic
  7. 关注边界安全:在所有 FFI 和 IPC 边界验证输入
决策框架
情况方法
共享所有权Arc<T>(线程安全)或 Rc<T>(单线程)
内部可变性Mutex<T>、RwLock<T> 或 RefCell<T>
性能关键场景先进行性能分析,再考虑 unsafe 优化
FFI 交互创建带验证的安全包装类型
错误处理返回带有自定义错误类型的 Result<T, E>

3. 技术基础

版本建议
类别版本说明
LTS/稳定版Rust 1.75+Tauri 2.x 的最低要求
推荐Rust 1.82+包含安全补丁的最新稳定版
Tauri2.0+新项目请使用 2.x
Tokio1.35+异步运行时
安全依赖
[dependencies]
serde = { version = "1.0", features = ["derive"] }
validator = { version = "0.16", features = ["derive"] }
ring = "0.17"              # Cryptography
argon2 = "0.5"             # Password hashing
dunce = "1.0"              # Safe path canonicalization

[dev-dependencies]
cargo-audit = "0.18"       # Vulnerability scanning

4. 实施工作流(TDD)

步骤 1:先编写失败的测试
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_user_creation_valid_input() {
        let input = UserInput { name: "Alice".to_string(), age: 30 };
        let result = User::try_from(input);
        assert!(result.is_ok());
        assert_eq!(result.unwrap().name, "Alice");
    }

    #[test]
    fn test_user_creation_rejects_empty_name() {
        let input = UserInput { name: "".to_string(), age: 25 };
        assert!(matches!(User::try_from(input), Err(AppError::Validation(_))));
    }

    #[tokio::test]
    async fn test_async_state_concurrent_access() {
        let state = AppState::new();
        let state_clone = state.clone();
        let handle = tokio::spawn(async move {
            state_clone.update_user("1", User::new("Bob")).await
        });
        state.update_user("2", User::new("Alice")).await.unwrap();
        handle.await.unwrap().unwrap();
        assert!(state.get_user("1").await.is_some());
    }
}
步骤 2:编写通过测试所需的最少代码
impl TryFrom<UserInput> for User {
    type Error = AppError;
    fn try_from(input: UserInput) -> Result<Self, Self::Error> {
        if input.name.is_empty() {
            return Err(AppError::Validation("Name cannot be empty".into()));
        }
        Ok(User { name: input.name, age: input.age })
    }
}
步骤 3:重构并验证
cargo test && cargo clippy -- -D warnings && cargo audit

5. 实施模式

模式 1:安全输入验证

使用 validator crate 和自定义正则表达式模式验证所有 Tauri 命令输入。

use serde::Deserialize;
use validator::Validate;

#[derive(Deserialize, Validate)]
pub struct UserInput {
    #[validate(length(min = 1, max = 100), regex(path = "SAFE_STRING_REGEX"))]
    pub name: String,
    #[validate(range(min = 0, max = 120))]
    pub age: u8,
}

#[tauri::command]
pub async fn create_user(input: UserInput) -> Result<User, String> {
    input.validate().map_err(|e| format!("Validation error: {}", e))?;
    Ok(User::new(input))
}

完整的验证模式及正则表达式定义请参见 references/advanced-patterns.md

模式 2:安全错误处理

使用 thiserror 定义结构化错误,以便安全地序列化,且不暴露内部细节。

use thiserror::Error;

#[derive(Error, Debug)]
pub enum AppError {
    #[error("Database error")]
    Database(#[from] sqlx::Error),
    #[error("Validation failed: {0}")]
    Validation(String),
    #[error("Not found")]
    NotFound,
}

impl serde::Serialize for AppError {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where S: serde::Serializer {
        serializer.serialize_str(&self.to_string()) // Never expose internals
    }
}
模式 3:安全文件操作

通过规范化路径并验证路径是否位于允许范围内,防止路径遍历。

pub fn safe_path_join(base: &Path, user_input: &str) -> Result<PathBuf, AppError> {
    if user_input.contains("..") || user_input.contains("~") {
        return Err(AppError::Validation("Invalid path characters".into()));
    }
    let canonical = dunce::canonicalize(base.join(user_input))
        .map_err(|_| AppError::NotFound)?;
    let base_canonical = dunce::canonicalize(base)
        .map_err(|_| AppError::Internal(anyhow::anyhow!("Invalid base")))?;

    if !canonical.starts_with(&base_canonical) {
        return Err(AppError::Validation("Path traversal detected".into()));
    }
    Ok(canonical)
}
模式 4:安全执行命令

通过使用允许列表并避免执行 shell,缓解 CVE-2024-24576。

pub fn safe_command(program: &str, args: &[&str]) -> Result<String, AppError> {
    const ALLOWED: &[&str] = &["git", "cargo", "rustc"];
    if !ALLOWED.contains(&program) {
        return Err(AppError::Validation("Program not allowed".into()));
    }

    let output = Command::new(program).args(args).output()
        .map_err(|e| AppError::Internal(e.into()))?;

    if output.status.success() {
        String::from_utf8(output.stdout).map_err(|e| AppError::Internal(e.into()))
    } else {
        Err(AppError::Internal(anyhow::anyhow!("Command failed")))
    }
}
模式 5:安全异步状态管理

在 Tauri 应用中使用 Arc<RwLock> 实现线程安全的共享状态。

pub struct AppState {
    users: Arc<RwLock<HashMap<String, User>>>,
    config: Arc<Config>,
}

impl AppState {
    pub async fn get_user(&self, id: &str) -> Option<User> {
        self.users.read().await.get(id).cloned()
    }

    pub async fn update_user(&self, id: &str, user: User) -> Result<(), AppError> {
        self.users.write().await.insert(id.to_string(), user);
        Ok(())
    }
}

高级状态模式和 Tauri 集成请参见 references/advanced-patterns.md


6. 安全标准

5.1 严重 CVE
CVE ID严重程度描述缓解措施
CVE-2024-24576严重通过批处理文件进行命令注入(Windows)使用 Rust 1.77.2+,避免使用 shell
CVE-2024-43402高对上述问题的修复不完整使用 Rust 1.81.0+
CVE-2021-28032高在 unsafe 代码中存在多个可变引用审查 unsafe 代码块

完整的 CVE 详情和缓解代码请参见 references/security-examples.md

5.2 OWASP Top 10 映射
类别风险主要缓解措施
A01 访问控制失效中在 Tauri 命令中验证权限
A03 注入高不通过 shell 执行命令,使用参数化查询
A04 不安全设计中使用类型系统强制执行不变量
A06 易受攻击的组件高定期运行 cargo-audit
5.3 输入验证策略

四层方法:类型系统 newtype -> 模式验证(serde/validator)-> 业务逻辑 -> 输出编码

pub struct Email(String);  // Newtype for validated input

impl Email {
    pub fn new(s: &str) -> Result<Self, ValidationError> {
        if validator::validate_email(s) { Ok(Self(s.to_string())) }
        else { Err(ValidationError::InvalidEmail) }
    }
}
5.4 密钥管理
// Load from environment or tauri-plugin-store with encryption
fn get_api_key() -> Result<String, AppError> {
    std::env::var("API_KEY")
        .map_err(|_| AppError::Configuration("API_KEY not set".into()))
}

安全存储模式请参见 references/security-examples.md


7. 性能模式

模式 1:零拷贝操作

不佳:使用 data.to_vec() 后再迭代 - 良好:返回带生命周期的迭代器

// Bad: fn process(data: &[u8]) -> Vec<u8> { data.to_vec().iter().map(|b| b+1).collect() }
fn process(data: &[u8]) -> impl Iterator<Item = u8> + '_ {
    data.iter().map(|b| b + 1)  // No allocation
}
模式 2:使用迭代器链代替循环

不佳:手动循环并调用 push - 良好:使用迭代器链(惰性、融合)

fn filter_transform(items: &[Item]) -> Vec<String> {
    items.iter().filter(|i| i.is_valid()).map(|i| i.name.to_uppercase()).collect()
}
模式 3:为频繁分配使用内存池

不佳:在热点路径中使用 Vec::with_capacity() - 良好:使用对象池

static BUFFER_POOL: Lazy<Pool<Vec<u8>>> = Lazy::new(|| Pool::new(32, || Vec::with_capacity(1024)));

async fn handle_request(data: &[u8]) -> Vec<u8> {
    let mut buffer = BUFFER_POOL.pull(|| Vec::with_capacity(1024));
    buffer.clear(); process(&mut buffer, data); buffer.to_vec()
}
模式 4:选择异步运行时

不佳:在异步任务中执行 CPU 工作 - 良好:对 CPU 密集型任务使用 spawn_blocking

async fn hash_password(password: String) -> Result<String, AppError> {
    tokio::task::spawn_blocking(move || {
        argon2::hash_encoded(password.as_bytes(), &salt, &config)
            .map_err(|e| AppError::Internal(e.into()))
    }).await?
}
模式 5:避免在热点路径中分配内存

不佳:println! 会分配内存 - 良好:使用 write! 写入预分配缓冲区

fn log_metric(buffer: &mut Vec<u8>, name: &str, value: u64) {
    buffer.clear();
    write!(buffer, "{}: {}", name, value).unwrap();
    std::io::stdout().write_all(buffer).unwrap();
}

8. 测试与验证

安全测试命令
cargo audit                          # Dependency vulnerabilities
cargo +nightly careful test          # Memory safety checking
cargo clippy -- -D warnings          # Lint with security warnings
单元测试模式
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_path_traversal_blocked() {
        let base = Path::new("/app/data");
        assert!(safe_path_join(base, "../etc/passwd").is_err());
        assert!(safe_path_join(base, "user/file.txt").is_ok());
    }

    #[test]
    fn test_command_allowlist() {
        assert!(safe_command("rm", &["-rf", "/"]).is_err());
        assert!(safe_command("git", &["status"]).is_ok());
    }
}

模糊测试和集成测试模式请参见 references/advanced-patterns.md


9. 常见错误与反模式

反模式问题解决方案
在生产代码中使用 .unwrap()panic 会导致应用崩溃对 Result 使用 ?
使用 unsafe 却没有文档说明不变量未经验证添加 // SAFETY: 注释
执行 shell 命令注入漏洞直接使用 Command::new()
忽略 Clippy遗漏安全 lint运行 cargo clippy -- -D warnings
凭据硬编码密钥写在代码中使用环境变量或安全存储
// NEVER: Shell injection
Command::new("sh").arg("-c").arg(format!("echo {}", user_input));

// ALWAYS: Direct execution
Command::new("echo").arg(user_input);

10. 实施前检查清单

阶段 1:编写代码前
  • 编写会失败的测试,以定义预期行为
  • 查看与该功能领域相关的 CVE
  • 确定安全边界(FFI、IPC、文件系统)
  • 使用 Result 类型规划错误处理策略
  • 使用 cargo audit 检查依赖项
阶段 2:实施期间
  • 每次重大更改后运行测试
  • 使用 // SAFETY: 注释为所有 unsafe 代码块添加文档说明
  • 在所有边界处验证输入(Tauri 命令、FFI)
  • 使用类型系统强制执行不变量(newtype)
  • 应用性能模式(零拷贝、迭代器)
  • 确保错误消息不会泄露内部细节
阶段 3:提交前
  • cargo test - 所有测试均通过
  • cargo clippy -- -D warnings - 无警告
  • cargo audit - HIGH/CRITICAL 漏洞数量为零
  • 不包含硬编码密钥(搜索 "password"、"secret"、"key")
  • 路径操作使用规范化和包含性检查
  • 命令执行使用允许列表,不使用 shell
  • 配置 panic 处理程序,以实现平稳关闭
  • 配置日志记录(日志中不包含密钥)

11. 总结

你的目标是编写符合以下要求的 Rust 代码:

  • 内存安全:利用借用检查器,尽量减少 unsafe
  • 类型安全:利用类型系统防止无效状态
  • 高性能:使用零成本抽象,优化前先进行性能分析
  • 安全:在边界处进行验证,并安全地处理错误

重要安全提醒:

  1. 升级到 Rust 1.81.0+,以修复命令注入 CVE
  2. 在 CI/CD 流水线中运行 cargo-audit
  3. 为所有 unsafe 块记录 SAFETY 不变量
  4. 切勿使用 Shell 执行用户输入
  5. 规范化并验证所有文件路径

如需查看详细示例和高级模式,请参阅 references/ 目录

评论

支持 Markdown