64d6812ec3
- requirements.txt: 添加 passlib[bcrypt] 依赖 - deploy-server/nginx.conf: /ws/ 路径添加 access_log off - docs/ADRs/: 新增 4 个 ADR 决策记录 - docs/SOPs/: 新增 4 个 SOP 操作规程
81 lines
2.5 KiB
Markdown
81 lines
2.5 KiB
Markdown
# 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 不留痕
|
|
- ⚠️ 旧客户端需更新(发版通知)
|