138 lines
7.4 KiB
Markdown
138 lines
7.4 KiB
Markdown
# 安全扫描报告(静态审计)
|
||
|
||
日期: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`
|