Files
csm/CLAUDE.md
iven 60ee38a3c2 feat: 新增补丁管理和异常检测插件及相关功能
feat(protocol): 添加补丁管理和行为指标协议类型
feat(client): 实现补丁管理插件采集功能
feat(server): 添加补丁管理和异常检测API
feat(database): 新增补丁状态和异常检测相关表
feat(web): 添加补丁管理和异常检测前端页面
fix(security): 增强输入验证和防注入保护
refactor(auth): 重构认证检查逻辑
perf(service): 优化Windows服务恢复策略
style: 统一健康评分显示样式
docs: 更新知识库文档
2026-04-11 15:59:53 +08:00

6.3 KiB
Raw Permalink Blame History

CSM — 企业终端安全管理系统

知识库: @wiki/index.md — 编译后的模块化知识,新会话加载即了解全貌。

项目概览

CSM (Client Security Manager) 是一个医院设备终端安全管控平台,采用 C/S + Web 管理面板三层架构。

[Web 管理面板]  --HTTP/WS-->  [Server]  --自定义 TCP 二进制协议-->  [Client 代理]
 Vue3+ElementPlus            Axum+SQLite                       Windows 服务/控制台
 端口 9997(dev)              HTTP:9998 WS:/ws TCP:9999

Workspace 结构

Crate 职责 关键技术
csm-protocol Frame 编解码、MessageType 枚举、payload 结构体 serde, thiserror
csm-server HTTP API、TCP 接入、数据库、WebSocket 推送 axum, sqlx, JWT, rustls
csm-client 设备监控、插件采集、Windows 服务 tokio, sysinfo, windows-rs

依赖方向: serverprotocolclient。Server 和 Client 之间不直接依赖。

前端

Vue 3 + TypeScript + Vite + Element Plus + Pinia + ECharts。源码在 web/src/


编码规范

Rust

  • 错误处理: anyhow::Result 作为顶层返回类型,thiserror 定义库级错误枚举
  • 日志: 使用 tracing (info!/warn!/error!/debug!),禁止 println!
  • 序列化: 所有网络传输使用 JSON (serde + serde_json)
  • 时间: chrono::Utc::now().to_rfc3339(),数据库统一用 datetime('now')
  • Windows-only 代码使用 #[cfg(target_os = "windows")] 门控,非 Windows 提供 Vec::new() 空实现
  • PowerShell 调用使用 tokio::process::Command (异步),参数 -NoProfile -NonInteractive -Command

API 响应

统一 ApiResponse<T> 信封:{ success, data, error }。分页用 Pagination 结构体(默认 page=1, page_size=20, 上限 100)。

数据库

  • 使用 sqlx 手写 SQL + 参数绑定 (.bind()),绝不拼接 SQL
  • INSERT 使用 ON CONFLICT ... DO UPDATE 做 upsert
  • 迁移只追加,永不修改已有文件
  • 外键启用,时间列统一命名 created_at / updated_at / reported_at

命名

类型 约定 示例
MessageType 枚举 PascalCase WebFilterRuleUpdate
数据库表 snake_case clipboard_violations
API 路由 kebab-case /api/plugins/web-filter/rules
环境变量 CSM_ 前缀 UPPER_SNAKE CSM_SERVER, CSM_USE_TLS
客户端插件目录 snake_case clipboard_control/mod.rs

二进制协议

MAGIC(4B) + VERSION(1B) + TYPE(1B) + LENGTH(4B) + PAYLOAD(变长)
"CSM\0"    0x01         0x01-0x95   big-endian u32   JSON bytes

最大 payload 4MB。MessageType 按插件分块: 0x1x=核心, 0x2x=上网, 0x3x=时长, 0x4x=软件, 0x5x=弹窗, 0x6x=U盘文件, 0x7x=水印/USB策略, 0x8x=插件控制, 0x9x=加密/打印/剪贴板。


插件开发

客户端插件模板

每个客户端插件遵循统一模式:

// crates/client/src/<plugin>/mod.rs
#[derive(Debug, Clone, Default)]
pub struct PluginConfig { pub enabled: bool, /* ... */ }

pub async fn start(
    mut config_rx: watch::Receiver<PluginConfig>,
    data_tx: mpsc::Sender<Frame>,
    device_uid: String,
) {
    let mut config = config_rx.borrow_and_update().clone();
    let mut interval = tokio::time::interval(/* ... */);
    interval.tick().await;
    loop {
        tokio::select! {
            result = config_rx.changed() => { if result.is_err() { break; } /* 更新 config */ }
            _ = interval.tick() => { if !config.enabled { continue; } /* 采集上报 */ }
        }
    }
}

新增插件必改文件清单

按顺序检查,每个都必须改:

  1. crates/protocol/src/message.rs — 添加 MessageType 枚举值 + payload struct
  2. crates/protocol/src/lib.rs — re-export 新类型
  3. crates/client/src/<plugin>/mod.rs — 创建插件实现
  4. crates/client/src/main.rsmod <plugin>, watch channel, PluginChannels 字段, spawn 任务
  5. crates/client/src/network/mod.rs — PluginChannels 字段, handle_server_message 分支, handle_plugin_control 分支
  6. crates/server/src/api/plugins/<plugin>.rs — 创建 API handler
  7. crates/server/src/api/plugins/mod.rs — mod 声明 + 路由注册
  8. crates/server/src/tcp.rs — process_frame 新分支 + push_all_plugin_configs 初始推送
  9. crates/server/src/db.rs — DeviceRepo 新增 DB 操作方法
  10. migrations/NNN_<name>.sql — 新迁移文件
  11. crates/server/src/main.rs — include_str! 新迁移

配置推送三级作用域

push_to_targets() 支持 global / group / device,优先级 device > group > global。


安全

  • JWT access(30min) + refresh(7d) + token family 轮换防重放
  • 密码: bcrypt cost=12
  • 心跳 HMAC-SHA256 签名验证
  • 登录限流: 5 分钟窗口 10 次
  • API 路由三层权限: 公开 / 认证 / admin
  • HTTP 安全头: CSP, X-Frame-Options, X-Content-Type-Options
  • 敏感数据(如剪贴板)只上报元数据 [N chars],不存原文
  • 帧速率限制: 100 帧/5秒/连接

常见陷阱

  • 不要忘记 verify_device_uid: 每个 process_frame 分支必须在处理前验证发送者身份
  • 不要在 API 响应中泄露内部错误: 使用 ApiResponse::internal_error() 隐藏详情
  • 不要忘记 upsert 中的 updated_at: INSERT ON CONFLICT DO UPDATE 时必须更新 updated_at = datetime('now')
  • 不要在新 API handler 中引用不存在的列: SQL SELECT 的列必须与 migration DDL 完全匹配
  • 不要在异步任务中执行阻塞 IO: PowerShell 用 tokio::process::Command
  • 断线后清空 stale 数据: try_recv 循环 drain channel
  • 新增 payload struct 必须同时在 lib.rs re-export: 否则其他 crate 无法使用
  • print_audit 等轮询插件必须做去重: 记录 last_seen_timestamp只上报新事件

构建与运行

# 全量构建
cargo build --workspace
cargo build --release --workspace   # LTO + strip + size 优化

# 服务端
cargo run -p csm-server             # 读取 config.toml

# 客户端 (控制台模式)
cargo run -p csm-client
# 环境变量: CSM_SERVER, CSM_REGISTRATION_TOKEN, CSM_USE_TLS

# 客户端 (Windows 服务)
cargo run -p csm-client -- --install
cargo run -p csm-client -- --uninstall
cargo run -p csm-client -- --service

# 前端
cd web && npm install && npm run dev    # dev server :9997
cd web && npm run build                 # 产物 web/dist/