feat(protocol): 添加补丁管理和行为指标协议类型 feat(client): 实现补丁管理插件采集功能 feat(server): 添加补丁管理和异常检测API feat(database): 新增补丁状态和异常检测相关表 feat(web): 添加补丁管理和异常检测前端页面 fix(security): 增强输入验证和防注入保护 refactor(auth): 重构认证检查逻辑 perf(service): 优化Windows服务恢复策略 style: 统一健康评分显示样式 docs: 更新知识库文档
6.3 KiB
6.3 KiB
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 |
依赖方向: server → protocol ← client。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; } /* 采集上报 */ }
}
}
}
新增插件必改文件清单
按顺序检查,每个都必须改:
crates/protocol/src/message.rs— 添加 MessageType 枚举值 + payload structcrates/protocol/src/lib.rs— re-export 新类型crates/client/src/<plugin>/mod.rs— 创建插件实现crates/client/src/main.rs—mod <plugin>, watch channel, PluginChannels 字段, spawn 任务crates/client/src/network/mod.rs— PluginChannels 字段, handle_server_message 分支, handle_plugin_control 分支crates/server/src/api/plugins/<plugin>.rs— 创建 API handlercrates/server/src/api/plugins/mod.rs— mod 声明 + 路由注册crates/server/src/tcp.rs— process_frame 新分支 + push_all_plugin_configs 初始推送crates/server/src/db.rs— DeviceRepo 新增 DB 操作方法migrations/NNN_<name>.sql— 新迁移文件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/