fix: P0遗留修复 + ADR/SOP文档
- requirements.txt: 添加 passlib[bcrypt] 依赖 - deploy-server/nginx.conf: /ws/ 路径添加 access_log off - docs/ADRs/: 新增 4 个 ADR 决策记录 - docs/SOPs/: 新增 4 个 SOP 操作规程
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
# ADR-002: WebSocket Token 鉴权(走 Sec-WebSocket-Protocol)
|
||||
|
||||
**状态**: ✅ 已采纳
|
||||
**日期**: 2026-06-14
|
||||
**决策者**: 宋献 + Claude 评审
|
||||
**关联**: [[风险跟踪表]] 第十节 / 评审报告 `workbuddy-2026-06-14-P0安全.md`
|
||||
|
||||
---
|
||||
|
||||
## 1. 背景
|
||||
|
||||
WebSocket 鉴权原方案:`ws://server/ws/?token=<JWT>` —— **token 在 URL 里**:
|
||||
- ❌ 被 nginx access_log 记录
|
||||
- ❌ 被 CDN / 反代记录
|
||||
- ❌ 被浏览器历史记录
|
||||
|
||||
**P0 漏洞**(H-11 风险项),已修复。
|
||||
|
||||
## 2. 评估方案
|
||||
|
||||
| 方案 | 浏览器支持 | token 泄露 | 实施难度 | 结论 |
|
||||
|---|---|---|---|---|
|
||||
| **A. Authorization: Bearer header** | ❌ 浏览器 WS API 不支持自定义 header | ✅ 不泄 | 中 | ❌ 否决(浏览器限制) |
|
||||
| **B. Sec-WebSocket-Protocol: bearer.<token>** | ✅ 现代浏览器都支持 | ✅ 不在 URL | 低 | ✅ **采纳** |
|
||||
| **C. 第一条消息传 token** | ✅ 全支持 | ⚠️ 需先开 WS 接受任意连接(无法鉴权) | 低 | ❌ 否决 |
|
||||
| **D. Cookie 自动带** | ✅ 全支持 | ⚠️ CSRF 风险 | 中 | ❌ 否决 |
|
||||
|
||||
## 3. 决策
|
||||
|
||||
**采纳 B 方案**: `Sec-WebSocket-Protocol: bearer.<token>`
|
||||
|
||||
服务端协商 subprotocol,客户端用第二个 subprotocol 传 token(浏览器 API `new WebSocket(url, [subprotocols])`)。
|
||||
|
||||
## 4. 实现
|
||||
|
||||
### 4.1 前端
|
||||
|
||||
```ts
|
||||
// frontend-agent/src/composables/useWebSocket.ts
|
||||
const ws = new WebSocket(wsUrl, [`bearer.${agentStore.token}`])
|
||||
```
|
||||
|
||||
### 4.2 后端
|
||||
|
||||
```python
|
||||
# backend/app/api/ws.py
|
||||
subprotocol = request.headers.get("sec-websocket-protocol", "")
|
||||
if subprotocol.startswith("bearer."):
|
||||
token = subprotocol[7:]
|
||||
else:
|
||||
# 降级:Authorization header
|
||||
auth = request.headers.get("Authorization", "")
|
||||
if auth.startswith("Bearer "):
|
||||
token = auth[7:]
|
||||
else:
|
||||
# 降级:query param(已废,只用于兼容旧前端)
|
||||
token = request.query_params.get("token", "")
|
||||
```
|
||||
|
||||
## 5. 降级路径
|
||||
|
||||
| 优先级 | 来源 | 用途 |
|
||||
|---|---|---|
|
||||
| 1 | Sec-WebSocket-Protocol | 标准(主) |
|
||||
| 2 | Authorization: Bearer | Postman / 测试工具 |
|
||||
| 3 | query `?token=` | 已废(留兼容) |
|
||||
|
||||
## 6. 风险与缓解
|
||||
|
||||
| 风险 | 缓解 |
|
||||
|---|---|
|
||||
| 浏览器 API 不支持 subprotocol | 现代浏览器(2020+)都支持,无问题 |
|
||||
| 旧客户端不更新 | query param 降级仍可用,但提示更新 |
|
||||
| nginx 仍记录 subprotocol | `location /ws/ { access_log off; }` 配合 |
|
||||
|
||||
## 7. 决策影响
|
||||
|
||||
- ✅ WS 鉴权修复,token 不再泄
|
||||
- ✅ nginx access_log 关闭,旧 token 不留痕
|
||||
- ⚠️ 旧客户端需更新(发版通知)
|
||||
Reference in New Issue
Block a user