- 新增磁盘加密、打印审计和剪贴板管控插件支持 - 优化水印插件显示效果,支持中文及更多Unicode字符 - 改进硬件资产收集逻辑,更准确获取磁盘和显卡信息 - 增强API错误处理,添加详细日志记录 - 完善前端界面,新增插件管理页面 - 修复多个UI问题,优化页面过渡效果 - 添加环境变量覆盖配置功能 - 实现插件状态管理API - 更新文档和变更日志 - 添加安装程序脚本支持
173 lines
6.2 KiB
Markdown
173 lines
6.2 KiB
Markdown
# CSM — 企业终端安全管理系统
|
||
|
||
## 项目概览
|
||
|
||
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=加密/打印/剪贴板。
|
||
|
||
---
|
||
|
||
## 插件开发
|
||
|
||
### 客户端插件模板
|
||
|
||
每个客户端插件遵循统一模式:
|
||
|
||
```rust
|
||
// 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.rs` — `mod <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,只上报新事件
|
||
|
||
---
|
||
|
||
## 构建与运行
|
||
|
||
```bash
|
||
# 全量构建
|
||
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/
|
||
```
|