Files
zkxw/docs/testing/2026-10-16-security-scan-report.md
T
2026-10-17 11:46:53 +08:00

138 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 安全扫描报告(静态审计)
日期: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`