# 安全扫描报告(静态审计) 日期:2026-10-16 方法:方案 A — 静态代码检索 + 关键路径人工研判 范围:`backend/app/`、`web-admin/src/`、`mobile-oa-h5/src/`、`mobile-h5/`、`miniprogram/`(业务源码) 排除:`venv/`、`node_modules/`、`web-admin/public/tinymce/`、纯 Demo HTML **本次不改业务代码**;下列「建议」供后续专项修复使用。 ## 摘要 | 风险 | 数量 | |------|------| | 高 | 0 | | 中 | 2 | | 低 | 3 | | 信息 | 4 | 结论概要: - **未发现**典型的「用户输入直接拼进 SQL 字符串」的经典 SQL 注入(业务 CRUD 大量使用 SQLAlchemy ORM / 绑定参数 `text(...):param`)。 - **存在**工作流「SQL 审批人」动态执行路径:黑名单不完整;前后端字段名不一致(`sqlExpr` vs `sql`)可能使该能力当前未真正生效,但代码路径本身具备风险。 - **XSS**:商品详情查看已走 `sanitizeHtml`;其余 `v-html`/`innerHTML` 多为固定资源或已 `escapeHtml`,风险较低。 - **弱口令**:文档与基线默认 `admin` / `111111`;请用配套脚本将库中明文等价 `111111` 的账号改为 `Zkxw@123`。 --- ## 问题清单 ### M-01 工作流 SQL 审批人:动态执行 SELECT,黑名单可绕过 - **风险**:中 - **位置**:`backend/app/services/workflow_engine.py`(约 26–28、306–317 行)`_resolve_approvers` / `_FORBIDDEN_SQL_KEYWORDS` - **简述**:当审批节点 `strategy == "sql"` 时,引擎对流程定义中的 SQL 模板执行 `db.execute(text(sql_template), variables)`。虽要求以 `SELECT` 开头并禁止 `INSERT/UPDATE/DELETE/DROP/ALTER/CREATE/TRUNCATE`,但未限制 `UNION`、多语句、`INTO OUTFILE`、`LOAD_FILE`、耗时函数等;流程变量以绑定参数传入相对安全,**SQL 模板本身**若被有流程设计权限的账号写入恶意语句,可造成越权读库或影响可用性。 - **建议**:仅允许预置白名单查询或受控 DSL;禁止自由 SQL;若必须保留,使用只读库账号 + 强制单语句解析 + 禁止分号/UNION/文件操作关键字;严格限制可编辑流程定义的角色。 ### M-02 流程设计器与引擎 SQL 字段名不一致(`sqlExpr` vs `sql`) - **风险**:中(安全相关功能缺陷;修复不当会放大 M-01) - **位置**: - 前端:`web-admin/src/views/system/workflow/designer/FlowDesigner.vue`(约 202–209、889 行)`config.sqlExpr` - 后端:`backend/app/services/workflow_engine.py`(约 307 行)`config.get("sql", "")` - **简述**:设计器保存的是 `sqlExpr`,引擎读取的是 `sql`。当前可能导致 SQL 策略实际取不到语句而失败;若后续只改一端对齐字段而**未**加固 M-01,会意外开启动态 SQL 执行面。 - **建议**:统一字段名并做端到端测试;同时落实 M-01 加固后再启用。 ### L-01 ThemeSvg:`fetch(src)` 后 `v-html` 渲染 SVG - **风险**:低 - **位置**:`web-admin/src/components/core/theme/theme-svg/index.vue`(约 5、61–74 行) - **简述**:将 `src` 拉取的文本直接 `v-html`。当前调用方(如登录页)传入本地/静态 SVG 路径,利用面小;若将来 `src` 可被不可信来源控制,SVG 内嵌脚本可能构成 XSS。 - **建议**:限制 `src` 为同源静态资源白名单;或对 SVG 做消毒后再渲染。 ### L-02 ArtTextScroll:`v-html="text"` 未消毒 - **风险**:低 - **位置**:`web-admin/src/components/core/text-effect/art-text-scroll/index.vue`(约 23、29 行) - **简述**:`text` 属性直接 `v-html`。业务侧若传入用户/运营可编辑的 HTML,存在 XSS;当前主要被节日滚动等内部组件使用。 - **建议**:默认按纯文本渲染,或统一走 `sanitizeHtml`。 ### L-03 highlight 指令:依赖调用方提供的 HTML - **风险**:低 - **位置**:`web-admin/src/directives/business/highlight.ts`(注释示例约 21 行;处理约 56–69、190 行) - **简述**:假定宿主已用 `v-html` 注入代码内容后再做行号等处理。若业务把不可信内容直接 `v-html` 再挂指令,会有 XSS。 - **建议**:文档标明仅用于可信演示内容;业务展示代码用转义或消毒。 ### I-01 默认弱口令文档与基线账号 - **风险**:信息 - **位置**:`AGENTS.md`、`backend/README.md`、`deploy/docker/README.md`(`admin` / `111111`) - **简述**:默认口令便于本地联调,若生产未轮换则属高危配置问题(由弱密码刷新脚本处理库内口令)。 - **建议**:生产执行 `backend/scripts/reset_weak_password_111111.py`;后续更新文档默认口令说明。 ### I-02 登录允许明文开关 - **风险**:信息 - **位置**:`backend/app/core/config.py`(约 169–170 行)`LOGIN_ALLOW_PLAINTEXT_LOGIN`(默认 `False`) - **简述**:生产若误开,登录凭据可能以明文进入请求体。 - **建议**:生产配置审计确保为 `false`。 ### I-03 API 加密 fail-open - **风险**:信息 - **位置**:`backend/app/core/config.py`(约 183–184 行)`API_ENCRYPT_FAIL_OPEN`(默认 `True`) - **简述**:加密中间件失败时放行,偏可用性;在加密本应强制的环境可能削弱传输层保护预期。 - **建议**:生产按安全要求评估是否关闭 fail-open。 ### I-04 商品详情富文本已消毒(正向记录) - **风险**:信息(良好实践) - **位置**:`web-admin/src/components/business/product-view-dialog/index.vue` + `web-admin/src/utils/sanitize-html.ts` - **简述**:查看弹窗 `v-html` 使用 `DOMPurify`(`sanitizeHtml`),降低存储型 XSS 风险。 - **建议**:其他富文本展示对齐同一工具。 --- ## 分类检索结论 ### SQL 注入 | 检查项 | 结果 | |--------|------| | `f"...SELECT/INSERT..."` / `%` / `.format` 拼 SQL | **未发现**(`backend/app`) | | `text()` 使用 | `biz_no_generator` / `sample_reception_lab_code` 等为**固定 SQL + 命名绑定参数**,未见用户输入拼进语句 | | 工作流动态 SQL | **见 M-01 / M-02** | | ORM `filter` 主路径 | 普遍使用绑定,未见字符串拼 WHERE | ### XSS | 检查项 | 结果 | |--------|------| | `web-admin` `v-html` | 商品详情已消毒;ThemeSvg / ArtTextScroll / highlight 见 L-01~L-03 | | `mobile-oa-h5` 打印 PDF | `exportOaApprovalPdf.js` 对展示字段使用 `escapeHtml` 后再 `innerHTML`,风险可控 | | `mobile-h5` `document.write` | 入口加载脚本用,非用户内容注入点 | | `miniprogram` | **未发现** `v-html` / `innerHTML` / `eval` 业务用法 | ### 其他 | 检查项 | 结果 | |--------|------| | 工作流 callback SSRF | `validate_callback_url` 禁止 http(s),仅本地注册路径 — 正向 | | 密码存储 | bcrypt(`app/core/security.py`)— 正向 | | 依赖 CVE / 渗透 / 基础设施 | **未做**(超出本次范围) | --- ## 局限 1. 静态审计不能替代动态渗透与鉴权矩阵测试(水平越权、IDOR 等需接口级用例)。 2. 未扫描第三方依赖 CVE、容器/主机配置、MinIO/Redis 网络暴露。 3. Demo / 文档 HTML 中的 `innerHTML` 未计入生产风险。 ## 配套交付 - 弱密码刷新脚本:`backend/scripts/reset_weak_password_111111.py` - SQL 说明:`docs/sql/2026-10-16-reset-weak-password-111111.sql` - 设计说明:`docs/superpowers/specs/2026-10-16-security-scan-and-weak-password-design.md`