记录 4 路并行审计发现、修复清单、刻意不改项及理由、安全结论、通用教训。 配套 cluster-recall #5785。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3.4 KiB
3.4 KiB
全面审计报告 — 2026-07-21
方法: 4 路并行子代理审计(core / modules / wiring+UI / security),逐条交叉验证后修复。 提交:
fix/audit-hardening(db73b34) | cluster-recall #5785 验证闭环:node --check语法全检 +yinji-cli冒烟/状态/批量/端到端 + UI 截图 + CSP 违规检查
已修复(8 类, 11 文件)
| 严重度 | 文件 | 缺陷 | 修复 |
|---|---|---|---|
| HIGH | main.js:1071 | 键盘快捷键不判焦点: 坐标框 Backspace 删印章、方向键移印章、旋转框输不了负号、文本框 Ctrl+C/V/S 被劫持 | handler 开头加焦点守卫(INPUT/TEXTAREA/SELECT/contenteditable/isComposing → return) |
| HIGH | seal-library.js:19 | getSavedSeals 不校验数组,脏 localStorage 打死印章库读/写/渲染 |
Array.isArray 校验 + isValidSeal 逐项过滤 + 格式异常自动重置 |
| MED | seal-library.js:260 | loadAndApplySeal 无 onerror + 成功 toast 在 onload 外同步弹 |
toast 移入 onload、补 onerror、handler 先于 src 赋值 |
| MED | canvas-manager.js:113 / context-menu.js:42 | 右键不选中对象 → 菜单不出现或作用于旧对象 | 开 fireRightClick/stopContextMenu,菜单前 findTarget 命中置活动对象 |
| MED | responsive.js:70-139 | 触摸手势死代码(_canvas 从不赋值) + body 全子树 MutationObserver 常驻空转 |
移除死代码链(fabric 自带触摸兜底),保留响应式布局 |
| LOW | exporter/batch-processing/batch-operations/settings (×5) | blob URL click() 后立即 revoke → 部分浏览器下载失败 |
延迟 setTimeout(revoke, 1000) |
| LOW | batch-processing.js:253 | 下载名 .replace('.pdf') 首次匹配+区分大小写+未 sanitize |
统一 generateSafeExportFilename |
| MED(加固) | index.html:9 / security.js | CSP 缺 object/frame 限制、无转义助手 | CSP 加 object-src 'none'; frame-ancestors 'none';补 escapeHtml() |
| INFO | tmp-global-patch-test-a.js | 根目录遗留测试残file | 删除 |
刻意不改(附理由)
- exporter 恒
degrees(0): 旋转烘焙进位图(getRotatedCroppedImage) + 对象lockRotation:true,正常使用不可能产生非零 angle,当前不可触发。 - state.js
setState浅拷贝: previousState 与集合/数组字段共享引用,但 batch-operations 已用new Set(...)防御拷贝规避。 - seal id
Date.now()毫秒碰撞: 手动操作极难触发。 - pdf.js
isEvalSupported: CSP 无unsafe-eval,eval 本就被拦。 - SVG 白名单(image/svg+xml): 经确认非 XSS 向量(仅经
<img>/fabric image 静态渲染,不执行脚本),保留功能。 - 移除
script-src 'unsafe-inline': 需搬 index.html 内联 lucide 初始化脚本,有回归风险,建议后续单独一项处理。
安全结论
未发现任何可实际利用的 XSS/注入。防护可信,但可信来自"全程用 textContent 而非 innerHTML 渲染不可信数据(文件名/印章名/签名/toast/dialog)"的编码纪律,而非集中转义工具。所有 innerHTML 均为开发者硬编码静态模板。fabric 反序列化为自写、只吃应用自身内存对象,不吃外部不可信 JSON。
通用教训(见 cluster-recall #5785)
- 全局键盘快捷键处理器必须判
e.target是否输入控件 +e.isComposing。 - localStorage 读取
JSON.parse后必须校验类型(Array.isArray)并逐项过滤脏数据。 - blob URL 下载应延迟 revoke。
image.onload必配onerror,成功提示放 onload 内。