缺陷单:敏感词/隐私正则/审计日志/命中配置 13 端点无鉴权(v1.1 实施漏加 require_admin)
缺陷编号: BUG-通用-004
版本: v1.0
状态: [待修复]
优先级: P0-Critical(合规/安全)
发现日期: 2026-08-05
发现人: 宋献
指派人: 宋献
修复人: Duckula (AI助手)
关联需求: REQ-通用-004(敏感词检测)
关联文档:
- PRD:
docs/01-产品文档/00-产品规划/PRD-REQ-通用-004-敏感词检测-v1.0.md(v1.2 待出)
- 技术方案:
docs/02-技术文档/技术架构/技术方案-REQ-通用-004-敏感词检测-v1.0.md(v1.2 待出)
- 任务说明书:
docs/07-项目管理/任务说明书/任务说明书-03-v1.1-敏感词词库入库+后台UI.md(v1.1 增量,即将归档为 .v1.1.archive.md)
- 源码:
src/backend/app/api/admin/sensitive_words.py
- 测试用例:
docs/03-测试文档/03-功能测试用例/TC-通用-004-敏感词检测.md
- 整改记录:
docs/04-运维文档/部署运维/00-文档规范化整改记录.md(#5 整改记录)
1. 基本信息
| 字段 |
内容 |
| 缺陷标题 |
src/backend/app/api/admin/sensitive_words.py 13 个端点全部未挂 Depends(require_admin),任何能访问 http://10.90.5.110:8000/api/admin/... 的内部用户均可直接调用,等同 admin 权限裸奔 |
| 影响范围 |
13 端点全覆盖:敏感词 CRUD/测试/重载 + 隐私正则 CRUD/测试 + 审计日志列表/统计 + 命中动作配置 |
| 涉及模块 |
后端 API(backend FastAPI, v1.1 新增路由) |
| 涉及文件 |
src/backend/app/api/admin/sensitive_words.py(仅此 1 个文件,APIRouter 未声明 dependencies=) |
| 触发条件 |
任意已登录用户(含坐席/普通员工)通过任何渠道获取 Bearer token 后直接调用这 13 个端点;或绕开前端直接 curl 后端 |
| 预期行为 |
调用 13 端点时若 agent.role != "admin",应抛出 AppException(1004, "无管理权限")(与 admin_api.py 行为一致) |
| 实际行为 |
13 端点全部 200 OK 通过;任何 token 持有者拥有增删改查敏感词库、读取审计日志(含员工消息片段)、上传任意正则(可触发 ReDoS)、触发 /sensitive-words/reload 强制热加载词库的能力 |
1.1 端点清单(v1.1 实施,13 个)
| 类别 |
方法 |
路径 |
用途 |
| 敏感词 |
GET |
/api/admin/sensitive-words |
词库列表(分页+筛选) |
| 敏感词 |
POST |
/api/admin/sensitive-words |
新增词 |
| 敏感词 |
PUT |
/api/admin/sensitive-words/{id} |
更新词 |
| 敏感词 |
DELETE |
/api/admin/sensitive-words/{id} |
删除词(软删) |
| 敏感词 |
POST |
/api/admin/sensitive-words/test |
测试输入文本 |
| 敏感词 |
POST |
/api/admin/sensitive-words/reload |
强制从 DB 热加载词库 |
| 隐私正则 |
GET |
/api/admin/privacy-patterns |
列表 |
| 隐私正则 |
POST |
/api/admin/privacy-patterns |
新增 |
| 隐私正则 |
PUT |
/api/admin/privacy-patterns/{id} |
更新 |
| 隐私正则 |
POST |
/api/admin/privacy-patterns/{id}/test |
正则测试器(ReDoS 入口) |
| 审计日志 |
GET |
/api/admin/moderation-logs |
列表(含 message_id/agent_id/matched_words/text_excerpt) |
| 审计日志 |
GET |
/api/admin/moderation-logs/stats |
统计 |
| 命中配置 |
GET |
/api/admin/moderation-config |
全局命中动作配置 |
2. 复现步骤
2.1 复现 1:词库列表裸奔(GET)
预期:HTTP 401/403,返回 {"code": 1004, "message": "无管理权限"}
实际:HTTP 200,返回完整词库(含 profanity/politics/porn 等所有分类与 severity)
2.2 复现 2:审计日志裸奔(GET)
预期:HTTP 401/403
实际:HTTP 200,返回 [{agent_id, matched_words, category, action, text_excerpt, created_at}, ...],含员工与坐席对话内容片段
2.3 复现 3:词库篡改(POST/PUT/DELETE)
2.4 复现 4:正则测试器 ReDoS(POST)
2.5 复现 5:热加载触发(POST /reload)
3. 根因分析
3.1 实现层:APIRouter 未声明 dependencies
sensitive_words.py:44 创建 router 时未附加 dependencies=[Depends(require_admin)]:
3.2 对比层:同类 admin 路由全部正确
| 文件 |
require_admin 覆盖 |
admin_api.py |
✅ 每个端点 Depends(require_admin) |
admin_roles.py |
✅ 已加 |
admin_users.py |
✅ 已加 |
welcome.py |
✅ 已加 |
quiz_admin.py |
✅ 已加 |
troubleshooting_templates.py |
✅ 已加 |
admin/sensitive_words.py |
❌ 13 端点全部漏挂 |
3.3 规范层:v1.1 实施未走 spec.md 强制约束
- 技术方案 v1.0 §6.3 路由层表格已明确列出所有 11 个端点的"权限:admin"
- PRD v1.0 §5.2 路由层 API 计划清单同样声明 admin 权限
- v1.1 实施时(任务说明书 v1.1)未对照规范逐项实现
- 任务说明书也未在验收用例里写"13 端点必须 401" → 测试环节也漏了
3.4 三层根因(缺一不可)
| 层 |
问题 |
体现 |
| 规范 |
v1.1 任务说明书验收清单缺"鉴权用例" |
§5 输出成果要求未列鉴权维度 |
| 实现 |
APIRouter 未声明 dependencies |
sensitive_words.py:44 |
| 测试 |
TC-通用-004 无鉴权章节 |
31 用例全在功能维度,无安全维度 |
4. 修复方案
4.1 最小修复(一行代码)
修改 src/backend/app/api/admin/sensitive_words.py:44:
4.2 文档同步(按 product-doc-standard 铁律)
| 文档 |
动作 |
| PRD v1.0 |
升级到 v1.2,加 §11 v1.1 增量 + §12 v1.2 安全补漏(鉴权) |
| 技术方案 v1.0 |
升级到 v1.2,§6.3 路由层表格的"权限"列追加"+ 鉴权依赖:Depends(require_admin) |
| 任务说明书 v1.1 |
旧名 .v1.1.archive.md 归档;新建 v1.2 覆盖鉴权补漏 |
| TC-通用-004 |
末尾追加 §10 鉴权用例(4 条) |
| 整改记录 |
在 00-文档规范化整改记录.md 追加 #5 整改条目 |
| Bug 单 |
本文件 |
4.3 代码变更清单
| 文件 |
变更类型 |
内容 |
src/backend/app/api/admin/sensitive_words.py |
修改 |
imports 增加 require_admin;router 加 dependencies=[Depends(require_admin)] |
src/backend/tests/ |
新增 |
test_sensitive_words_auth.py(鉴权测试 6 条) |
5. 验证方式
5.1 单元/集成测试(自动化)
| 用例 |
预期 |
| 无 token 调用 13 端点 |
401 |
| 普通坐席(role=agent)调用 13 端点 |
403 + code:1004 无管理权限 |
| 管理员(role=admin)调用 13 端点 |
200 |
| 重载/正则测试等写操作管理员调用 |
200 |
修复后源码 grep Depends(require_admin) |
应在 sensitive_words.py 出现至少 1 次 |
5.2 容器内端到端验证(修复后必做)
docker compose restart backend
docker compose exec backend grep -n "require_admin" app/api/admin/sensitive_words.py
- 用普通坐席 token curl 13 端点 → 应全部 401/403
- 用 admin token curl 13 端点 → 应全部 200
5.3 回归测试
- v1.1 既有 11 个功能测试用例全部通过
- TC-通用-004 §10 新增鉴权用例 4 条全部通过
6. 关联
| 类型 |
文档 |
| 规范 |
docs/00-产品开发流程与文档管理规范.md(v1.9)§ 4.3 文档更新时机 + § 11 文档整改实践 |
| 需求 |
REQ-通用-004 敏感词检测 |
| 上游实现 |
src/backend/app/services/content_moderation_service.py(v1.0 已上线审核服务) |
| 上游实现 |
src/backend/app/services/admin/sensitive_word_service.py(v1.1 词库入库 + 管理 service) |
| 数据库迁移 |
src/backend/alembic/versions/056_add_moderation_tables.py |
| 初始化数据 |
src/backend/scripts/init_moderation.sql |
| 测试基线 |
src/backend/tests/test_content_moderation.py(13 用例基线) |
| 对照 admin 路由 |
src/backend/app/api/admin_api.py:50 require_admin 定义 |
7. 变更记录
| 日期 |
版本 |
变更内容 |
变更人 |
变更原因 |
影响范围 |
| 2026-08-05 |
v1.0 |
首次登记:13 端点无鉴权缺陷 + 修复方案 + 文档同步清单 |
宋献 / Duckula |
v1.1 实施时漏加 require_admin 依赖,违反 PRD v1.0 §5.2 + 技术方案 v1.0 §6.3 admin 权限约束 |
13 端点全覆盖;后端 FastAPI 安全维度补漏;PRD/技术方案/任务说明书升级 v1.2 |