unis_crm/系统测试报告-20260903.md

10 KiB
Raw Blame History

UNIS CRM 系统测试报告

  • 测试日期2026-09-03
  • 测试环境:本机开发环境(后端 127.0.0.1:8080CRM 前端 3000/3002数据库/Redis 192.168.124.202
  • 测试账号:管理员 admin_crm (userId=19)、普通账号 13752913297/周瑾·部门领导 (userId=20)
  • 测试方式API 全量扫描 + 越权/安全专项测试 + 后端单元测试 + 前端构建验证

一、总体结论

系统核心业务功能基本正常(登录/刷新、工作台、商机管理、渠道拓展、归属转移、签到/日报、经营分析、导出等主流程均可跑通,错误提示友好,前端两个工程均可成功构建),但存在 2 个严重安全问题、若干高危缺陷,建议在上线前优先修复。

等级 数量 概述
🔴 严重 2 X-User-Id 伪造身份越权;管理配置接口无鉴权(含密钥泄露、可被任意用户改写)
🟠 2 全局异常处理缺陷(大量 500JWT 密钥使用仓库默认值
🟡 3 CORS 全开;单测失败 2 例;验证码禁用无防爆破
4 OMS 回调占位 token中英文报错混杂密钥硬编码设计确认项

二、正常功能清单(已验证通过

模块 验证内容 结果
认证 登录、错误密码统一提示、token 刷新、刷新后旧 token 失效(会话轮换)、伪造/篡改 token 被会话绑定校验拦截
工作台 /api/dashboard/home欢迎信息/统计/待办/动态)、待办完成、消息已读
经营分析 卡片列表数据、单卡片详情、管理端配置读取与预览
商机管理 meta/overview2102条/详情/oms售前选项、创建含逐步字段校验、编辑、跟进记录、删除不存在的资源有正确报错
渠道拓展 meta/城市级联(含无效省份返回空)/overview/form-options/crm-overview、表单校验
归属转移 target-users、preview普通接口强制"原归属人=当前账号")、管理接口有权限码校验
工作日报 签到(需关联对象+现场照片+定位)、照片上传(MinIO)、日报提交、历史查询、导出、逆地理编码(腾讯地图,含越界/非数字校验)
权限隔离(正常路径) 语音识别配置、数据授权配置对普通用户正确返回"无权";商机创建有 opportunity:create 权限校验
内部集成接口 /api/opportunities/integration/update 的 X-Internal-Secret 校验有效
企业微信 SSO /api/wecom/sso/entry 正确 302 到企业微信 OAuth
构建 frontendvite build 、frontend1vite build )、后端编译

三、缺陷清单

🔴 BUG-01【严重】后端完全信任客户端 X-User-Id 请求头,任意登录用户可冒充其他用户

  • 位置:所有 /api/* 业务 ControllerOpportunityControllerDashboardController 等)通过 @RequestHeader("X-User-Id") 获取当前用户,CurrentUserUtils.requireCurrentUserId() 只校验非空,不校验与 token 身份一致
  • 复现(普通用户 token + 管理员 userId 即可读到管理员数据):
    curl -H "Authorization: Bearer <普通用户token>" -H "X-User-Id: 19" \
         http://127.0.0.1:8080/api/dashboard/home
    # 返回 crm管理员 的首页数据userId=19, realName=crm管理员
    
  • 影响:横向/纵向越权——查看他人首页、个人概览、商机、日报、导出他人签到/日报数据;配合数据权限体系被整体绕过(周瑾本人已配置全量可见,但任何低权限用户均可伪造 19/43/… 任意 userId
  • 建议:在安全过滤器中以 JWT claims 覆盖/校验 X-User-Id(不一致即 403或改为从 SecurityContext 取当前用户

🔴 BUG-02【严重】/sys/api/admin 多个管理配置接口无任何权限校验(可读可写、密钥明文泄露、跨租户)

  • 位置ReportReminderAdminControllerDashboardAnalyticsAdminController(控制器与 Service 层均无 admin 校验)
  • 受影响接口(普通用户 token 直接访问,全部返回 200
    • GET/PUT /sys/api/admin/wecom-app-config —— 企微 corpId/agentId/secret 明文返回PUT 无字段校验,{} 即可清空配置(已实测并当场恢复);?tenantId=1 可跨租户读取
    • GET/PUT /sys/api/admin/report-reminder-configPOST /sys/api/admin/report-reminder-config/testtest 接口可被滥用向员工发企微消息)
    • GET/PUT /sys/api/admin/dashboard-analytics-config(及 preview、calendar/sync-current-year
    • GET /sys/api/admin/wecom-config-statusGET /sys/api/admin/report-reminder-calendar-status
  • 对照:同目录下 speech-recognition-configuser-data-scope/* 有 Service 层权限校验(普通用户 401"无权查看",说明这是部分接口遗漏
  • 建议:为上述接口统一增加与 speech/user-data-scope 相同的权限校验;企微 secret 不应明文回显(脱敏显示)

🟠 BUG-03【高】全局异常处理缺陷参数缺失 / JSON 解析错误 / 类型不匹配 一律返回 500

  • 位置CrmGlobalExceptionHandler 未覆盖 MissingServletRequestParameterExceptionHttpMessageNotReadableExceptionMethodArgumentTypeMismatchException
  • 复现实例(全部返回 500"系统内部错误",应为 400 + 明确提示):
    • GET /api/dashboard/analytics-cards/data(缺 cardKeys
    • GET /api/expansion/areas/cities(缺 provinceName
    • GET /api/owner-transfer/preview(缺 fromUserId/toUserId曾因传错参数名 sourceUserId 触发)
    • GET /sys/api/admin/user-data-scope/assignment(缺参数)
    • POST /sys/auth/refresh(无效 refreshToken
    • POST /api/opportunities{"amount":"abc"} 或非法 JSON
    • POST /api/wecom/sso/exchange(伪造 ticketGET /api/wecom/sso/js-sdk-config(缺 url
  • 建议:补充对应 @ExceptionHandler返回 400 与字段级错误信息,避免前端展示"系统内部错误"

🟠 BUG-04【高】运行环境使用仓库内默认 JWT 密钥

  • 证据:用 application.yml 中的默认值 change-me-please-change-me-32bytes 签发的 token签名校验通过(返回"Login expired"会话校验失败,而非"Invalid token"签名失败)——证明当前 8080 实例就是用该默认密钥签发 token
  • 现状缓解unisbase 框架有 sessionId↔userId 的 Redis 会话绑定校验,单纯伪造 payload 会被拦截;但任何拿到源码的人已具备签名能力,一旦会话校验有任何绕过即全面失守
  • 建议立即更换为强随机密钥并走环境变量注入prod 配置里同为此默认值)

🟡 BUG-05【中】CORS 配置全开

  • 证据:任意 Origin: http://evil.example.com 都被反射为 Access-Control-Allow-Origin,且 Access-Control-Allow-Credentials: true
  • 影响:结合 BUG-01/02恶意站点可借用户浏览器凭证发起跨域读操作
  • 建议CORS 白名单化,仅允许已知前端域名

🟡 BUG-06【中】后端单元测试 2/113 失败

  • ExpansionServiceImplTest.createChannelExpansion_shouldRejectDuplicateChannelName:期望"渠道重复…",实际先抛"请完整填写渠道联系人的姓名、职务…"
  • ExpansionServiceImplTest.updateChannelExpansion_shouldCheckDuplicateChannelNameExcludingSelf:同类错误
  • 原因:联系人必填校验(normalizeRequiredContacts)先于渠道重名校验执行,且测试夹具未包含完整联系人信息——测试与最新校验逻辑未同步(或校验顺序需调整:重名提示应优先于字段完整性)
  • 建议:补齐测试数据或调整校验顺序后修复用例

🟡 BUG-07【中】登录验证码被禁用无防爆破机制

  • GET /sys/auth/captcha 返回 500 "Captcha disabled",登录接口不校验验证码,也无失败锁定(配置中 max-attempts: 5 未生效)
  • 建议生产环境启用验证码或登录失败限流Redis 计数)

BUG-08【低】OMS 回调接口为占位实现且不可用

  • OmsCallbackController:硬编码占位 token your_secret_token_here;该路径未加入 permit-all先被全局过滤器 401 拦截(实际调不通);处理逻辑为 TODO 空壳
  • 建议:要么实现(配置化 token + 加入 permit-all + 白名单),要么移除

BUG-09【低】报错文案中英文混杂

  • 会话失效时框架层返回英文 "Login expired",业务层返回中文"登录已失效,请重新登录";前端需同时兼容两种文案
  • 建议:统一国际化

BUG-10【低】敏感信息硬编码入库

  • application.yml / application-prod.yml 中明文包含:数据库/Redis/MinIO 密码、企微 secret、内部集成 secret、OMS apiKey、腾讯地图 keyprod 与 dev 相同)
  • 建议:全部改环境变量注入,并轮换已泄露密钥

CONFIRM-01【设计确认】普通账号数据权限为全租户

  • 周瑾部门领导userId=20可见全部 2102 条商机(与其他用户数据一致)、全量经营分析卡片、全员签到/日报导出。数据授权表sys_user_data_scope_user中她无任何显式授权推测来自 unisbase DataScope 的角色规则
  • 请确认:部门领导是否应具有全租户数据可见权;经营分析(全公司金额 46478 万)是否应对普通员工开放

四、测试遗留数据(均可识别、可清理)

类型 ID 归属 标识
商机 2228 周瑾(20) 【自动化测试】请勿使用-权限验证
商机 2229 admin(19) 【自动化测试】请勿使用-权限验证
签到 1025 周瑾(20) 地点前缀【自动化测试】
日报 999 周瑾(20) 内容前缀【自动化测试】
签到照片 20-20d874400111404ebe2aa48fad846576.jpg MinIO

注:测试中曾意外清空租户 4 企微应用配置BUG-02 复现所致),已当场用原值恢复并二次验证一致。商机 2229 曾被改名/改金额用于越权验证,已恢复。

五、修复优先级建议

  1. 立即BUG-01X-User-Id 校验、BUG-02admin 接口鉴权 + secret 脱敏、BUG-04更换 JWT 密钥)
  2. 本周BUG-03异常处理器补齐、BUG-05CORS 白名单、BUG-06修复单测
  3. 排期BUG-07/08/09/10 及 CONFIRM-01 设计确认