mirror of
https://github.com/openimsdk/open-im-server.git
synced 2026-06-30 23:08:38 +08:00
676 lines
10 KiB
Markdown
676 lines
10 KiB
Markdown
# Virgil Security 接入到聊天系统设计方案(服务器)
|
||
|
||
## 1. 服务器设计目标
|
||
|
||
服务端的目标不是参与解密,而是提供 **业务承载层**:
|
||
|
||
- 业务身份认证
|
||
- 设备管理
|
||
- Virgil JWT 签发
|
||
- 单聊/群聊会话管理
|
||
- 密文消息接入与路由
|
||
- 离线同步
|
||
- 文件上传/下载票据
|
||
- 群成员关系与群密钥版本索引
|
||
- 风控与设备吊销
|
||
|
||
---
|
||
|
||
## 2. 服务器总体架构
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
subgraph Backend["业务服务端"]
|
||
B1["API Gateway"]
|
||
B2["Auth Service"]
|
||
B3["Virgil JWT Service"]
|
||
B4["Conversation Service"]
|
||
B5["Message Router / Sync"]
|
||
B6["Group Service"]
|
||
B7["Push Service"]
|
||
B8["File Ticket Service"]
|
||
B9["Risk / Device Service"]
|
||
B10["Metadata DB"]
|
||
end
|
||
|
||
subgraph Virgil["Virgil Cloud"]
|
||
V1["Cards / Public Key Directory"]
|
||
V2["Restore Related Services"]
|
||
end
|
||
|
||
subgraph OSS["Object Storage / CDN"]
|
||
O1["Encrypted File Objects"]
|
||
end
|
||
|
||
B1 --> B2
|
||
B1 --> B3
|
||
B1 --> B4
|
||
B1 --> B5
|
||
B1 --> B6
|
||
B1 --> B8
|
||
B1 --> B9
|
||
|
||
B2 --> B10
|
||
B3 --> B10
|
||
B4 --> B10
|
||
B5 --> B10
|
||
B6 --> B10
|
||
B8 --> O1
|
||
B9 --> B10
|
||
|
||
B3 --> V1
|
||
B3 --> V2
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 服务器职责边界
|
||
|
||
## 3.1 服务端应该负责什么
|
||
|
||
- 用户登录与 token
|
||
- 设备注册与吊销
|
||
- Virgil JWT 签发
|
||
- 会话与群组元数据
|
||
- 密文消息存储
|
||
- 消息序列号与游标
|
||
- 离线消息投递
|
||
- 已读/已送达状态
|
||
- 文件票据
|
||
- 群成员变更事件
|
||
- 风控控制
|
||
|
||
## 3.2 服务端不应该负责什么
|
||
|
||
- 私钥保存
|
||
- 文本明文解析
|
||
- 文件明文解析
|
||
- 群密钥管理的明文操作
|
||
- 替客户端做消息加解密
|
||
|
||
---
|
||
|
||
## 4. 推荐服务拆分
|
||
|
||
```text
|
||
api-gateway
|
||
auth-service
|
||
virgil-jwt-service
|
||
conversation-service
|
||
message-service
|
||
group-service
|
||
sync-service
|
||
push-service
|
||
file-ticket-service
|
||
risk-device-service
|
||
```
|
||
|
||
### 各服务说明
|
||
|
||
#### api-gateway
|
||
- 统一入口
|
||
- 鉴权
|
||
- 请求限流
|
||
- trace 注入
|
||
|
||
#### auth-service
|
||
- 登录
|
||
- refresh
|
||
- logout
|
||
|
||
#### virgil-jwt-service
|
||
- 生成 Virgil JWT
|
||
- user/device 到 virgil identity 的映射
|
||
- 风控前置校验
|
||
|
||
#### conversation-service
|
||
- 单聊会话
|
||
- 会话设置
|
||
- 会话列表
|
||
|
||
#### message-service
|
||
- 接收密文 envelope
|
||
- 分配 message_id / seq
|
||
- 存储与 fanout
|
||
|
||
#### group-service
|
||
- 创建群
|
||
- 加人/踢人/退群
|
||
- 群资料
|
||
- 维护 group_key_version
|
||
|
||
#### sync-service
|
||
- bootstrap
|
||
- 增量消息
|
||
- 群事件同步
|
||
|
||
#### push-service
|
||
- message.new
|
||
- message.recall
|
||
- group.member_changed
|
||
- device.revoked
|
||
|
||
#### file-ticket-service
|
||
- 上传票据
|
||
- 下载票据
|
||
- 文件元信息
|
||
|
||
#### risk-device-service
|
||
- 设备状态
|
||
- 完整性校验
|
||
- 风险拦截
|
||
|
||
---
|
||
|
||
## 5. 服务端数据模型
|
||
|
||
## 5.1 用户与设备
|
||
|
||
```mermaid
|
||
erDiagram
|
||
USER ||--o{ DEVICE : owns
|
||
USER {
|
||
string user_id
|
||
string status
|
||
int64 created_at
|
||
}
|
||
DEVICE {
|
||
string device_id
|
||
string user_id
|
||
string platform
|
||
string device_model
|
||
string app_version
|
||
string virgil_identity
|
||
string status
|
||
int64 last_seen_at
|
||
}
|
||
```
|
||
|
||
## 5.2 会话与消息
|
||
|
||
```mermaid
|
||
erDiagram
|
||
CONVERSATION ||--o{ MESSAGE : contains
|
||
CONVERSATION {
|
||
string conversation_id
|
||
string type
|
||
string peer_key
|
||
string group_id
|
||
int64 created_at
|
||
}
|
||
MESSAGE {
|
||
string message_id
|
||
string conversation_id
|
||
string chat_type
|
||
string sender_user_id
|
||
string sender_device_id
|
||
string receiver_user_id
|
||
string group_id
|
||
int64 group_key_version
|
||
string content_type
|
||
int envelope_version
|
||
string cipher_suite
|
||
bytes ciphertext
|
||
bytes signature
|
||
int64 seq
|
||
int64 server_timestamp
|
||
}
|
||
```
|
||
|
||
## 5.3 群与群事件
|
||
|
||
```mermaid
|
||
erDiagram
|
||
GROUP ||--o{ GROUP_MEMBER : has
|
||
GROUP ||--o{ GROUP_KEY_EVENT : emits
|
||
GROUP {
|
||
string group_id
|
||
string conversation_id
|
||
string owner_user_id
|
||
string name
|
||
int64 group_key_version
|
||
string status
|
||
}
|
||
GROUP_MEMBER {
|
||
string group_id
|
||
string user_id
|
||
string role
|
||
string status
|
||
int64 join_version
|
||
int64 leave_version
|
||
}
|
||
GROUP_KEY_EVENT {
|
||
string event_id
|
||
string group_id
|
||
int64 group_key_version
|
||
string event_type
|
||
string operator_user_id
|
||
int64 created_at
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 服务端接口设计
|
||
|
||
## 6.1 认证与设备
|
||
|
||
### 登录
|
||
```http
|
||
POST /api/v1/auth/login
|
||
```
|
||
|
||
### 刷新 token
|
||
```http
|
||
POST /api/v1/auth/refresh
|
||
```
|
||
|
||
### 登出
|
||
```http
|
||
POST /api/v1/auth/logout
|
||
```
|
||
|
||
### 注册设备
|
||
```http
|
||
POST /api/v1/devices/register
|
||
```
|
||
|
||
### 查询设备列表
|
||
```http
|
||
GET /api/v1/devices
|
||
```
|
||
|
||
### 吊销设备
|
||
```http
|
||
POST /api/v1/devices/{device_id}:revoke
|
||
```
|
||
|
||
---
|
||
|
||
## 6.2 Virgil JWT
|
||
|
||
### 获取 Virgil JWT
|
||
```http
|
||
POST /api/v1/security/virgil-jwt
|
||
```
|
||
|
||
请求:
|
||
```json
|
||
{
|
||
"device_id": "ios_a1"
|
||
}
|
||
```
|
||
|
||
响应:
|
||
```json
|
||
{
|
||
"virgil_jwt": "virgil_jwt_xxx",
|
||
"expires_in": 3600,
|
||
"virgil_identity": "u_1001:ios_a1"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 6.3 会话
|
||
|
||
### 创建/获取单聊
|
||
```http
|
||
POST /api/v1/conversations/single
|
||
```
|
||
|
||
### 会话列表
|
||
```http
|
||
GET /api/v1/conversations
|
||
```
|
||
|
||
### 会话详情
|
||
```http
|
||
GET /api/v1/conversations/{conversation_id}
|
||
```
|
||
|
||
### 会话设置
|
||
```http
|
||
POST /api/v1/conversations/{conversation_id}/settings
|
||
```
|
||
|
||
---
|
||
|
||
## 6.4 消息
|
||
|
||
### 发送消息
|
||
```http
|
||
POST /api/v1/messages
|
||
```
|
||
|
||
### 批量发送
|
||
```http
|
||
POST /api/v1/messages:batchSend
|
||
```
|
||
|
||
### 拉取指定消息
|
||
```http
|
||
GET /api/v1/messages/{message_id}
|
||
```
|
||
|
||
### 撤回消息
|
||
```http
|
||
POST /api/v1/messages/{message_id}:recall
|
||
```
|
||
|
||
### 仅自己删除
|
||
```http
|
||
POST /api/v1/messages/{message_id}:deleteForMe
|
||
```
|
||
|
||
---
|
||
|
||
## 6.5 群组
|
||
|
||
### 创建群
|
||
```http
|
||
POST /api/v1/groups
|
||
```
|
||
|
||
### 群详情
|
||
```http
|
||
GET /api/v1/groups/{group_id}
|
||
```
|
||
|
||
### 群上下文
|
||
```http
|
||
GET /api/v1/groups/{group_id}/context
|
||
```
|
||
|
||
### 群成员列表
|
||
```http
|
||
GET /api/v1/groups/{group_id}/members
|
||
```
|
||
|
||
### 加人
|
||
```http
|
||
POST /api/v1/groups/{group_id}/members:add
|
||
```
|
||
|
||
### 移除成员
|
||
```http
|
||
POST /api/v1/groups/{group_id}/members:remove
|
||
```
|
||
|
||
### 退群
|
||
```http
|
||
POST /api/v1/groups/{group_id}:leave
|
||
```
|
||
|
||
### 解散群
|
||
```http
|
||
POST /api/v1/groups/{group_id}:dismiss
|
||
```
|
||
|
||
### 修改群资料
|
||
```http
|
||
POST /api/v1/groups/{group_id}/profile
|
||
```
|
||
|
||
---
|
||
|
||
## 6.6 文件
|
||
|
||
### 申请上传票据
|
||
```http
|
||
POST /api/v1/files/upload-ticket
|
||
```
|
||
|
||
### 上传完成
|
||
```http
|
||
POST /api/v1/files/{file_id}:complete
|
||
```
|
||
|
||
### 获取下载票据
|
||
```http
|
||
POST /api/v1/files/{file_id}/download-ticket
|
||
```
|
||
|
||
### 获取文件元信息
|
||
```http
|
||
GET /api/v1/files/{file_id}
|
||
```
|
||
|
||
---
|
||
|
||
## 6.7 同步
|
||
|
||
### 冷启动 bootstrap
|
||
```http
|
||
GET /api/v1/sync/bootstrap
|
||
```
|
||
|
||
### 增量消息同步
|
||
```http
|
||
GET /api/v1/sync/messages
|
||
```
|
||
|
||
### 群事件同步
|
||
```http
|
||
GET /api/v1/sync/group-events
|
||
```
|
||
|
||
---
|
||
|
||
## 6.8 回执与状态
|
||
|
||
### 已送达/已读
|
||
```http
|
||
POST /api/v1/messages/ack
|
||
```
|
||
|
||
### 批量已读
|
||
```http
|
||
POST /api/v1/conversations/{conversation_id}:markRead
|
||
```
|
||
|
||
### 输入中
|
||
```http
|
||
POST /api/v1/conversations/{conversation_id}/typing
|
||
```
|
||
|
||
---
|
||
|
||
## 6.9 风控与安全
|
||
|
||
### 预检查
|
||
```http
|
||
POST /api/v1/security/precheck
|
||
```
|
||
|
||
### 设备完整性上报
|
||
```http
|
||
POST /api/v1/security/integrity-report
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 服务端核心流程
|
||
|
||
## 7.1 签发 Virgil JWT
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant C as 客户端
|
||
participant J as Virgil JWT Service
|
||
participant A as Auth Service
|
||
participant R as Risk / Device Service
|
||
|
||
C->>J: /security/virgil-jwt
|
||
J->>A: 校验 access_token
|
||
A-->>J: 用户有效
|
||
|
||
J->>R: 校验 device_id / 风险状态
|
||
R-->>J: 允许或拒绝
|
||
|
||
J-->>C: 返回 virgil_jwt
|
||
```
|
||
|
||
## 7.2 消息接收与路由
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant C as 客户端
|
||
participant M as Message Service
|
||
participant S as Sync Service
|
||
participant P as Push Service
|
||
participant DB as Metadata DB
|
||
|
||
C->>M: POST /messages
|
||
M->>DB: 存储 envelope
|
||
M->>DB: 分配 message_id / seq
|
||
M->>S: 写离线同步流
|
||
M->>P: 触发新消息推送
|
||
M-->>C: 返回 accepted
|
||
```
|
||
|
||
## 7.3 群成员变更
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant A as 管理员客户端
|
||
participant G as Group Service
|
||
participant DB as Metadata DB
|
||
participant S as Sync Service
|
||
participant P as Push Service
|
||
|
||
A->>G: /groups/{id}/members:add
|
||
G->>DB: 更新群成员
|
||
G->>DB: group_key_version + 1
|
||
G->>S: 写入 group event
|
||
G->>P: 推送 group.member_changed
|
||
G-->>A: 返回最新 group_key_version
|
||
```
|
||
|
||
---
|
||
|
||
## 8. 服务端幂等与校验
|
||
|
||
## 8.1 幂等设计
|
||
|
||
### 发消息幂等键
|
||
|
||
推荐:
|
||
|
||
```text
|
||
sender_user_id + sender_device_id + client_message_id
|
||
```
|
||
|
||
### 创建群幂等
|
||
|
||
推荐使用:
|
||
|
||
```http
|
||
Idempotency-Key: <uuid>
|
||
```
|
||
|
||
## 8.2 消息接口校验项
|
||
|
||
- 当前用户是会话参与者
|
||
- `sender_device_id` 属于当前用户
|
||
- 单聊的 `receiver_user_id` 与会话匹配
|
||
- 群聊的 `group_id` 与会话匹配
|
||
- 当前用户是群成员
|
||
- `group_key_version` 合法
|
||
- `ciphertext` 长度不超过限制
|
||
|
||
## 8.3 Virgil JWT 接口校验项
|
||
|
||
- 业务 token 有效
|
||
- `device_id` 属于当前用户
|
||
- 设备状态为 active
|
||
- 未被吊销
|
||
- 风控未阻断
|
||
|
||
---
|
||
|
||
## 9. WebSocket / 推送事件建议
|
||
|
||
### WebSocket 事件
|
||
|
||
- `message.new`
|
||
- `message.recall`
|
||
- `message.ack`
|
||
- `group.member_changed`
|
||
- `group.profile_changed`
|
||
- `device.revoked`
|
||
- `security.force_logout`
|
||
|
||
### 推送原则
|
||
|
||
推送中不要放消息明文,建议只放:
|
||
|
||
- 会话 ID
|
||
- 发送方昵称
|
||
- 占位提示
|
||
|
||
---
|
||
|
||
## 10. 服务端风险点
|
||
|
||
- 若服务端误记录明文日志,会破坏 E2EE 边界
|
||
- 若文件下载链接长期有效,文件密文泄露面会扩大
|
||
- 若群成员变更后未提升 `group_key_version`,客户端可能使用旧上下文
|
||
- 若被吊销设备仍可获取 Virgil JWT,会造成安全失控
|
||
- 若推送带明文,会绕过加密链路
|
||
|
||
---
|
||
|
||
## 11. 推荐实施路径
|
||
|
||
## 阶段 1:单聊 MVP
|
||
|
||
实现:
|
||
|
||
- 登录
|
||
- Virgil JWT
|
||
- 单聊消息发送
|
||
- 增量同步
|
||
- 已读回执
|
||
|
||
## 阶段 2:群聊
|
||
|
||
实现:
|
||
|
||
- 创建群
|
||
- 群成员管理
|
||
- group_key_version
|
||
- 群事件同步
|
||
|
||
## 阶段 3:文件与恢复
|
||
|
||
实现:
|
||
|
||
- 文件票据
|
||
- 加密文件上传下载
|
||
- 新设备恢复
|
||
- 风控增强
|
||
|
||
---
|
||
|
||
## 12. 服务器总结
|
||
|
||
服务器在 Virgil Security 接入中的核心定位是:
|
||
|
||
- 不参与消息解密
|
||
- 不保存私钥
|
||
- 只处理密文、元数据和业务控制逻辑
|
||
|
||
具体来说,服务器负责:
|
||
|
||
- 身份认证
|
||
- 设备管理
|
||
- Virgil JWT 签发
|
||
- 密文消息接入、存储、路由
|
||
- 会话与群成员关系
|
||
- 文件票据
|
||
- 同步与推送
|
||
- 风控和设备吊销
|
||
|
||
这样才能既保留现有聊天系统的业务能力,又维持端到端加密的安全边界。
|