Files
wecom_it_smart_desk/docs/03-测试文档/05-缺陷单/BUG-通用-004-敏感词API无鉴权-001.md
T
Simon facc04aa65 chore: docs 结构整改 + compose 双目录对齐(合并重建提交)
本提交为 .git 对象库损坏后的重建提交,内容等价于原先三个本地提交
(5e2fd4c2 / 57a53c98 / 5d7e1873)的累积结果,未做任何额外改动。

一、docs 结构整改(整改 #14)
根因:重构时新结构为 untracked 文件,执行 git stash(未带 -u)未纳入,
随后 git reset 拉回 HEAD 旧 tracked 树,导致旧树复活、新旧两棵目录
树并存于 docs/,共 791 文件、双分类体系冲突。

修复动作:
- b2 同名异主题文件改名迁移保全 9 个
- C 类 39 个孤立文件按主题正确归类
- A/B1 类 222 个重复文件删除(新结构已有内容副本)
- 9 个旧独有空目录删除
- 270 处内部引用按 verified 映射改写
- 整改记录 #14 登记于 04-运维文档/部署运维

结果:docs 791 → 569 文件,顶层仅规范 8 类 + 治理文件,单树恢复。
残留:约 20 处指向从未存在文件的陈旧死链,归入独立文档卫生任务。

二、compose 双目录对齐(消除踩坑 A)
- docker-compose.yml:nginx 前端挂载全部由根目录 frontend-*/dist
  改为 src/frontend-*/dist(h5 / agent / admin / terminal)
- docker-compose.dev.yml:dev 服务 build context 与卷同步改 src/
- 效果:本地 docker compose up 不再把根目录 stale dist 挂回,
  与线上一致,分叉隐患消除(已 docker compose config 校验通过)

防复发铁律:
- 重构须提交;仓库修复须 git stash -u 或先 commit
- 新结构须 git add 并提交,避免再次 untracked 复活
- H5 改动只动 src/frontend-h5/,禁改根目录遗留 frontend-*/
2026-08-07 22:31:32 +08:00

10 KiB
Raw Blame History

缺陷单:敏感词/隐私正则/审计日志/命中配置 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.mdv1.2 待出)
  • 技术方案: docs/02-技术文档/技术架构/技术方案-REQ-通用-004-敏感词检测-v1.0.mdv1.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/测试 + 审计日志列表/统计 + 命中动作配置
涉及模块 后端 APIbackend 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)

# 任意坐席账号(role=agent,非 admin)的 Bearer token
TOKEN="<任意普通坐席 token>"

curl -sS -X GET "http://10.90.5.110:8000/api/admin/sensitive-words?page=1&page_size=20" \
  -H "Authorization: Bearer $TOKEN" -H "Accept: application/json"

预期HTTP 401/403,返回 {"code": 1004, "message": "无管理权限"} 实际:HTTP 200,返回完整词库(含 profanity/politics/porn 等所有分类与 severity

2.2 复现 2:审计日志裸奔(GET)

curl -sS -X GET "http://10.90.5.110:8000/api/admin/moderation-logs?page=1&page_size=20" \
  -H "Authorization: Bearer $TOKEN"

预期HTTP 401/403 实际HTTP 200,返回 [{agent_id, matched_words, category, action, text_excerpt, created_at}, ...],含员工与坐席对话内容片段

2.3 复现 3:词库篡改(POST/PUT/DELETE

# 任意 token 即可删除核心拦截词
curl -sS -X DELETE "http://10.90.5.110:8000/api/admin/sensitive-words/1" \
  -H "Authorization: Bearer $TOKEN"
# 实际:HTTP 200is_active=false,词条立即全局失效

2.4 复现 4:正则测试器 ReDoSPOST

curl -sS -X POST "http://10.90.5.110:8000/api/admin/privacy-patterns/1/test" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"pattern": "(a+)+$", "text": "aaaaaaaaaaaaaaaaaaaab"}'
# 实际:HTTP 200,触发 catastrophic backtrackingCPU 100% 数秒

2.5 复现 5:热加载触发(POST /reload

curl -sS -X POST "http://10.90.5.110:8000/api/admin/sensitive-words/reload" \
  -H "Authorization: Bearer $TOKEN"
# 实际:HTTP 200,全量重新加载词库到内存;高频调用可拖垮 DB + 后端

3. 根因分析

3.1 实现层:APIRouter 未声明 dependencies

sensitive_words.py:44 创建 router 时未附加 dependencies=[Depends(require_admin)]

# ❌ 错误(当前实现)
router = APIRouter(prefix="/admin", tags=["敏感词管理(v1.1"])

# ✅ 正确(应改为)
from app.api.admin_api import require_admin
router = APIRouter(
    prefix="/admin",
    tags=["敏感词管理(v1.1"],
    dependencies=[Depends(require_admin)],  # 一行全覆盖 13 端点
)

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

# 顶部 imports 增加
from app.api.admin_api import require_admin

# router 创建增加 dependencies
router = APIRouter(
    prefix="/admin",
    tags=["敏感词管理(v1.1"],
    dependencies=[Depends(require_admin)],  # 13 端点全覆盖
)

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_adminrouter 加 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 容器内端到端验证(修复后必做)

  1. docker compose restart backend
  2. docker compose exec backend grep -n "require_admin" app/api/admin/sensitive_words.py
  3. 用普通坐席 token curl 13 端点 → 应全部 401/403
  4. 用 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.pyv1.0 已上线审核服务)
上游实现 src/backend/app/services/admin/sensitive_word_service.pyv1.1 词库入库 + 管理 service
数据库迁移 src/backend/alembic/versions/056_add_moderation_tables.py
初始化数据 src/backend/scripts/init_moderation.sql
测试基线 src/backend/tests/test_content_moderation.py13 用例基线)
对照 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