20260921-audit-r3-restore.md 12 KB

第三轮审计整改 · R3 恢复组(R3-10 / R3-3 / R3-2)改动说明

① 头部

对照网址 http://39.97.59.228:8013/hrx/mky-vent-base/compare/master...fix/audit-r3-20260921
依据文档 代码审核-第三轮-mky-vent-base-20260921.md(该报告 A 组 A-1/A-2/A-3,对应本文档 R3-2/R3-3/R3-10)
分支 fix/audit-r3-20260921(本组原施工分支 fix/audit-r3-restore-20260921,已按提交 cherry-pick 汇入最终分支)
基线 upstream/master = 4e311cb6(behind=0,分支起点)
日期 2026-09-21(Asia/Shanghai)
交付版本 fix/audit-r3-20260921(7 个提交:bug 组 3 + 恢复组 4)
状态 已推 fork(origin = lizuo/mky-vent-base);未推 upstream、未推 master、未部署,待人工审核

总原则:本分支只恢复「地址配置化 / 凭据外置」两类形态不动自动登录/免密流程。 恢复来源为 09-14 已被人工审核"采纳"、但被团队 7e9858ec(回滚 13 文件)/c913dbf9 回退的 4b94efbddd5e7d808f87ade5 三个提交的内容。 红线文件 src/hooks/vent/useAutoLogin.tssrc/router/guard/permissionGuard.tssrc/store/modules/user.tsfireBD.vue/fire-green.vue?mock-login=1 链接均未改动git diff 可证)。

② 提交清单

# 标题
1 [Fix R3-10] 恢复 /modelreq 相对路径与 glob.wsUrl(去硬编码 IP:端口)
2 [Fix R3-3] autoLoginToken 回空值(凭据外置,部署注入)
3 [Fix R3-2] .env 删除 mock 免密凭据默认值(外置部署注入)
4 [Docs] 第三轮审计 R3 恢复组改动说明

只列提交标题、不写死 hash:本文件的这几条提交在汇入最终分支时被 cherry-pick,hash 会变 (旧稿写死的 3 个施工提交 hash 在最终分支上已不可达)。hash 一律以本分支 git log --oneline 为准。

③ 改动面

7 个代码文件 + 本说明(git diff --stat 实测:35 插入 / 13 删除):

文件 改动
public/mxcad/mxServerConfig.json saveDwgUrl 硬编码 IP:端口 → 站点相对路径 /modelreq/...?saveDwgUrl 说明注释写清来历
src/views/vent/home/configurable/configurable.data.ts 3 处 mp4 link(mainFan/fanLocal/gate)硬编码 IP:端口 → 相对路径,各加说明注释
src/layouts/default/header/components/VoiceBroadcast.vue WS 端点恢复读 glob.wsUrl + 加固(见 ④-3)
src/layouts/default/header/components/VoiceBroadcastGsd.vue 同上
public/fileEdit.html OnlyOffice api.js 硬编码公网地址 → 运行时配置 onlyOfficeUrl 下发(见 ⑦-1)
public/js/config.js autoLoginToken: 'MTIzNDU2'''(空 = 不携带该头)
.env 删除 VITE_MOCK_LOGIN_USERNAME/PASSWORD_CHAR_CODE 两个 mock 免密凭据键(原值 autoAdmin/autoAdmin123)

④ 逐项说明

R3-10 硬编码地址回退(恢复 4b94efbd

  1. mxServerConfig.json / configurable.data.ts(4 处)

    • 原行为:CAD 转 DWG 地址与 3 个看板视频写死旧云环境 IP:8092,换部署环境必须改代码。
    • 现行为:恢复为站点相对路径 /modelreq/...,同源经 nginx /modelreq 反代至网关(团队既有部署约定)。
    • 为什么:该改动 09-14 人工审核已采纳,被 7e9858ec 一并回退;属"敏感信息硬编码"口径。
    • 差别:仅地址形态变化,无逻辑变化。
  2. fileEdit.html(见 ⑦-1,超出 4 文件清单):同上原则,恢复运行时配置下发。

  3. VoiceBroadcast.vue / VoiceBroadcastGsd.vue(加固点)

    • 原行为(回退后):'http://' + hostname + ':9999'?.replace('https://','wss://').replace('http://','ws://') + ...。 这里 ?. 优先级使 replace 只作用于 ':9999' 字面量,返回仍是 ':9999'——协议改写从未生效, 实际拼出的是 http://<host>:9999/websocket/...(WS 构造器收到 http 协议头,行为依赖浏览器容错)。
    • 现行为:恢复 useGlobSetting().wsUrlpublic/js/config.js 单点配置,当前值 window.location.origin + '/modelreq'),并把 https://→wss://http://→ws:// 替换锚定在完整 URL 的协议头/ ^https:\/\///^http:\/\//,避免误改 URL 体内出现的 "http://" 子串); glob.wsUrl 缺失时回退 window.location.origin + '/modelreq'(协议取自 location.protocol, replace 后即正确推导 ws/wss)。
    • 为什么:既恢复运行期配置(去 :9999 硬编码直连),又修复从未生效的协议改写。
    • 差别:WS 端点由"网关端口 http 直连"变为"同源 /modelreq 反代(wss)"。前提:nginx 已把 /modelreq 的 WS 升级到网关——与 config.jswsUrl 的既有约定一致,非新引入依赖。

R3-3 autoLoginToken 回空值(撤销 c913dbf9,恢复 dd5e7d80

  • 原行为:c913dbf9 在仓库里写死 autoLoginToken: 'MTIzNDU2'(=123456,公开弱票据), 且部署 6 条 config.js 补丁不含该键 → 生产永远携带该弱票据。
  • 现行为:回 ''src/api/sys/user.ts:76 已实现 headers: VUE_APP_URL.autoLoginToken ? { token: ... } : {}——空 = 不携带该头, 服务端按"未配置自动登录令牌"明确拒绝(fail-closed)。
  • 为什么:autoLoginToken可选语义——空值即不携带该头,不能改成强制登录; 凭据应由部署环境注入(与服务端 SDJT_AUTO_LOGIN_TOKEN 配套),不应在仓库写死默认值
  • 差别:仅凭据形态(仓库内无默认票据)。未改动 src/api/sys/user.ts 的读取逻辑与任何免密流程。

R3-2 .env mock 免密凭据外置(恢复 8f87ade5 做法)

  • 原行为:.envVITE_MOCK_LOGIN_USERNAME_CHAR_CODE/PASSWORD_CHAR_CODE = autoAdmin/autoAdmin123, 随构建注入产物(.envVITE_* 必进 dist)。
  • 现行为:删除两个键(8f87ade5 的原始做法即删键;已验证删键不破坏构建)。 缺失时 src/store/constant.tsfromEnvCharCodes(undefined) → 返回 ''不抛错
  • 为什么:mock 免密凭据属"前端硬编码敏感信息"口径(§7.2 口径 1 明确"凭据仍按口径 1 审"), 流程本身不审(冻结项)。
  • 差别:仅删凭据默认值;user.ts/permissionGuard.ts 代码一行未动。

⑤ 验收证据

  1. WS URL 拼接逻辑实测(node 复现改后代码,4 个用例全对):
    • glob.wsUrl='http://a.b/modelreq'ws://a.b/modelreq/websocket/u1
    • glob.wsUrl='https://a.b/modelreq'wss://a.b/modelreq/websocket/u1
    • 缺失 + http:ws://a.b/modelreq/websocket/u1 ✅(回退推导正确)
    • 缺失 + https:wss://a.b/modelreq/websocket/u1
  2. public/js/config.jswsUrl 键确认存在grep -n wsUrl public/js/config.js → 第 4 行 wsUrl: window.location.origin + '/modelreq'types/global.d.ts:8 类型声明、src/hooks/setting/index.ts:87 读取均在)。
  3. .env 空值安全性验证结论(R3-2 前置验证,全部通过)
    • src/store/constant.ts:3-4fromEnvCharCodes 读取,其实现(src/utils/env.ts)首行 if (!charCodeStr) return '';——缺失/空串安全,返回空串,不抛错
    • 使用点全量排查(grep -rn "MOCK_LOGIN_UESRNAME\|MOCK_LOGIN_PASSWORD" src/): user.ts:93getIsMockLogin,空串与真实用户名比对恒 false,无副作用)、 user.ts:378-379mockLogin 参数,空串 → 免密请求带空凭据被服务端拒绝 = 预期行为)、 CADModal.vue 两处均已注释掉。build/vite.config.ts 对这两个键的强制校验。
    • 除"凭据为空导致免密请求失败"外其它行为变化:无类型错误(参数声明即 string | undefined 兼容)、 无构建失败、无 NPE(undefined === '' 为 false)。
    • 残余理论边角:getIsMockLogin 在"服务端返回的用户名恰为空串"时恒真,进而 401 时触发 redoMockLogin 重试—— 前提是真实用户名不可能为空串,判定为可接受风险,仅记录。
  4. 红线核对git diff 4e311cb6..HEAD --name-only 不含 useAutoLogin.ts/permissionGuard.ts/user.ts/ fireBD.vue/fire-green.vue/tools/

⑥ 静态检查

# Babel 语法检查(worktree node_modules 软链,@babel/parser 走 .pnpm 路径)
node -e "...parse(VoiceBroadcast.vue / VoiceBroadcastGsd.vue script / configurable.data.ts)..."
→ OK × 3

node --check public/js/config.js            → config.js syntax OK
node -e "JSON.parse(...mxServerConfig.json)" → JSON OK(该文件 "?key" 注释风格键名是合法 JSON 键,可严格解析)

# 残留复核(必须零命中)
grep -rn "182\.92\.126\.35\|47\.94\.222\.6" src public → 0 命中(exit 1)
grep -rn ":9999" src/layouts                                  → 0 命中(exit 1)

说明:改动处的说明注释刻意不写 IP/端口字面量(原值在 git 历史 4b94efbd/7e9858ec 可查), 以保证"残留 grep 零命中"这一验收口径本身可作为持续检查手段。未跑构建(按任务要求)。

⑦ 已知取舍

  1. public/fileEdit.html 超出任务所列 4 文件清单:任务验收要求"残留 grep 零命中", 而 fileEdit.html47.94.222.6:9050 同属 7e9858ec 回退的 R3-10 范畴(4b94efbd 已含该文件), 故一并恢复并在本节显式声明;如审核认为应拆分,可单独 revert「[Fix R3-10] 恢复 /modelreq 相对路径与 glob.wsUrl」那个提交中的该文件。
  2. 部署注入由父方处理:8092 的 6 条 config.js 补丁扩为 7 条(含 autoLoginToken)由父方在 tools/deploy/lib.sh 完成,本分支未触碰 tools/
  3. 免密/自动登录流程未动?mock-login=1 链接、useAutoLogin.tspermissionGuard.tsuser.ts 保持仓库现状;本分支只恢复"地址/凭据形态"。
  4. 说明注释中"原硬编码值"一律指向 git 历史而非直接书写,便于 grep 口径持续生效。
  5. 同文件另有两处硬编码地址,本轮未动(已立案、下一批处理)public/fileEdit.html:24document.url:38callbackUrl 仍写死 http://192.168.187.1:9999/ventanaly-sharefile/fileServer/onlyOffice/{read,save}
    • 事实:这两处在基线 4e311cb6 就存在git show 4e311cb6:public/fileEdit.html | grep -n 192.168.187.1 可证), 不是本轮引入;也不属第三轮审计条目 R3-10 的范围(该条目只针对 api.js47.94.222.6:9050)。
    • 为什么不顺手改:它们指向 sharefile 服务(不是 Document Server 的 api.js 前缀),且该文件含 [[${id}]] 模板占位、可能由后端另行渲染——改法需先确认调用链与 OnlyOffice 集成,属"需单独验证的改动",按规矩不夹带。
    • 处置:父方在 8092 产物验收中发现并立案(tools/verify/第三轮-独立复核与交叉检索-20260921.md P-13), 建议下一批与构建配置类改动(如 VITE_PROXY 内联,见 P-12)一并施工。

⑧ 交付状态与上游同步

  • 本组 4 个提交(R3-10 / R3-3 / R3-2 + 本文档)已 cherry-pick 汇入最终分支 fix/audit-r3-20260921,并已推 forkorigin = lizuo/mky-vent-base);未推 upstream、未推 master
  • 未部署、未触碰生产;
  • 基线 4e311cb6 = 当前 upstream/master,behind=0;
  • 待人工审核后由人工决定推送/合并。