65 lines
3.1 KiB
Markdown
65 lines
3.1 KiB
Markdown
|
|
# workbuddy 评审反馈 — 2026-06-14 P0 安全止血
|
||
|
|
|
||
|
|
**推送内容**: WS token 鉴权改造 + 坐席本地密码 + secret 管理规划文档
|
||
|
|
**评审日期**: 2026-06-14
|
||
|
|
**评审人**: Claude
|
||
|
|
**主报告**: `D:\资料\03-项目开发\wecom_it_smart_desk\docs\评审报告\workbuddy-2026-06-14-P0安全.md`
|
||
|
|
**commit**: 3735dc0 (本地 main,未推 Gitea)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## ⭐ 给 workbuddy 的关键反馈(高优先级)
|
||
|
|
|
||
|
|
1. **🔴 浏览器 WebSocket API 不支持自定义 header** — 误用 Node.js `ws` 库的 options.headers
|
||
|
|
2. **🔴 nginx access_log 没关** — 即使前端修好,token 仍经 access_log 泄露
|
||
|
|
3. **🟡 Mapped[str] + nullable=True 类型不一致** — 改 Optional[str]
|
||
|
|
4. **🟡 企微降级放行仍能绕过 password 验证** — P0-#5 被反削弱
|
||
|
|
5. **🟡 requirements.txt 缺 passlib** — 部署会 ImportError
|
||
|
|
|
||
|
|
## 🔴 遗留 5 项(下一轮必修)
|
||
|
|
|
||
|
|
| # | 严重度 | 文件 | 修复要点 |
|
||
|
|
|---|---|---|---|
|
||
|
|
| 1 | 🔴 P0 | `frontend-agent/.../useWebSocket.ts:106-110` | 改 `new WebSocket(wsUrl, [\`bearer.${token}\`])` + 服务端从 `sec-websocket-protocol` 取 |
|
||
|
|
| 2 | 🔴 P0 | `nginx.conf` + `deploy-server/nginx.conf` | 加 `location /ws/ { access_log off; }` |
|
||
|
|
| 3 | 🟡 P1 | `backend/app/models/agent.py:142-148` | `Mapped[str]` → `Mapped[Optional[str]]` |
|
||
|
|
| 4 | 🟡 P1 | `backend/app/api/agents.py` 降级放行 | 检测 `agent.password_hash` 存在 → 强制 password |
|
||
|
|
| 5 | 🟡 P1 | `backend/requirements.txt` | 加 `passlib[bcrypt]==1.7.4` 或改用原生 `bcrypt==4.1.2` |
|
||
|
|
|
||
|
|
## 🟢 评审验收
|
||
|
|
|
||
|
|
- ✅ ws.py 服务端:header 优先 + query 降级,**逻辑正确**
|
||
|
|
- ✅ model 字段定义:`password_hash` String(128) nullable,**结构 OK**(类型注解除外)
|
||
|
|
- ✅ schema:`AgentLogin.password` + `AgentPasswordUpdate`,**OK**
|
||
|
|
- ✅ 改密端点 `POST /agents/password`:走 `Depends(get_current_agent)`,**OK**
|
||
|
|
- ✅ alembic 008:down_revision='007_role_system' 正确,**OK**
|
||
|
|
- ✅ docs/安全/secret-管理.md:**作为规划文档 OK**
|
||
|
|
|
||
|
|
## 📊 完成度
|
||
|
|
|
||
|
|
| 任务 | 完成 |
|
||
|
|
|---|---|
|
||
|
|
| P0-#1 WECOM_SECRET 集中化 | 🟡 仅规划文档 |
|
||
|
|
| P0-#2 SSL 私钥在仓 | 🟢 之前已修(8-A 阶段) |
|
||
|
|
| P0-#3 Mock login | 🟢 之前已修 |
|
||
|
|
| P0-#4 WS token URL/日志 | 🟡 半成品(服务端 OK,前端 + nginx 待关) |
|
||
|
|
| P0-#5 坐席本地密码 | 🟡 半成品(模型/Schema/端点 OK,类型 + 降级 + 依赖) |
|
||
|
|
|
||
|
|
**整体**: 2/5 P0 真正完成,3 项遗留待下一轮。
|
||
|
|
|
||
|
|
## 🔁 流程建议
|
||
|
|
|
||
|
|
- 推送前自检清单:
|
||
|
|
- [ ] 浏览器 WebSocket API 边界(不要用 `ws` 库的 options.headers)
|
||
|
|
- [ ] nginx/conf 改动 plan 写了就必须做
|
||
|
|
- [ ] Mapped[T] + nullable=True 必须用 Optional
|
||
|
|
- [ ] 改代码必须同步 requirements.txt
|
||
|
|
- [ ] 加新鉴权必须 review 已有降级路径是否被绕过
|
||
|
|
- **强烈建议**: workbuddy 推送前先回答"我的改动在浏览器侧能跑吗?"(不要假设 Node.js API = 浏览器 API)
|
||
|
|
|
||
|
|
## 🔗 推 Gitea 状态
|
||
|
|
|
||
|
|
- **本地 commit 3735dc0**: ✅ 已存
|
||
|
|
- **推 Gitea**: 🔴 卡 #8(MariaDB 套件未装)
|
||
|
|
- **下次**: Gitea 起来后 `git push -u origin main` 推 → workbuddy 拿 Gitea URL 二次评审
|