council(draft): SecurityEngineer - Round 1 plan: AdminGoodsSaveHandle security audit
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>council/FrontendDev
parent
bdb4eb55e7
commit
325eb4116a
267
plan.md
267
plan.md
|
|
@ -49,270 +49,3 @@
|
||||||
|
|
||||||
- 依赖 `docs/VR_GOODS_CONFIG_SPEC.md`(v3.0 JSON 格式说明)
|
- 依赖 `docs/VR_GOODS_CONFIG_SPEC.md`(v3.0 JSON 格式说明)
|
||||||
- 不需要 BackendArchitect / DebugAgent 配合,可独立完成
|
- 不需要 BackendArchitect / DebugAgent 配合,可独立完成
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 问题总览
|
|
||||||
|
|
||||||
| # | 问题 | 症状 | 优先级 |
|
|
||||||
|---|------|------|--------|
|
|
||||||
| **P1** | 插件控制器路由无法渲染 | 内容区空白,"template not exists" | 高 |
|
|
||||||
| **P2** | 侧边栏插件名乱码 | `VR票务`(应为 `VR票务`) | 中 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## P1 — 路由无法渲染问题
|
|
||||||
|
|
||||||
### 已知现象
|
|
||||||
- 访问 `adminwatekc.php?s=VrTicket/SeatTemplateList` → 侧栏正常,主内容区空白
|
|
||||||
- ShopXO `Plugins/Index` 控制器调用插件时有 `strtolower+ucfirst` 类名匹配问题
|
|
||||||
- 当前 `SeatTemplate.php` 在 `admin/controller/` 子目录
|
|
||||||
|
|
||||||
### 已知正确模式(freightfee/answers)
|
|
||||||
```
|
|
||||||
app/plugins/{plugin}/
|
|
||||||
├── Admin.php ← 直接在插件根目录,继承 think\Controller
|
|
||||||
├── Hook.php
|
|
||||||
├── config.json
|
|
||||||
└── admin/view/... ← 视图在 admin/view/ 子目录
|
|
||||||
```
|
|
||||||
|
|
||||||
### 当前 vr_ticket 结构(有问题)
|
|
||||||
```
|
|
||||||
app/plugins/vr_ticket/
|
|
||||||
├── admin/controller/SeatTemplate.php ← ❌ 在子目录
|
|
||||||
└── admin/view/seat_template/list.html
|
|
||||||
```
|
|
||||||
|
|
||||||
### 任务清单
|
|
||||||
|
|
||||||
- [x] **P1-T1**: 验证 `strtolower+ucfirst` 路由匹配机制
|
|
||||||
- PluginsService::PluginsControlCall: `class = \app\plugins\{plugin}\{group}\{ucfirst(control)}`
|
|
||||||
- sidebar URL `/plugins/vr_ticket/admin/seatTemplateList`
|
|
||||||
- → pluginsname=vr_ticket, pluginscontrol=admin, pluginsaction=seatTemplateList
|
|
||||||
- → class = \app\plugins\vr_ticket\admin\Admin ✓
|
|
||||||
- → method = ucfirst('seatTemplateList') = 'SeatTemplateList' ✓
|
|
||||||
- [x] **P1-T2**: 对比 Admin.php 根目录模式 vs 当前 admin/controller/ 子目录模式
|
|
||||||
- 根目录 Admin.php (`app/plugins/vr_ticket/admin/Admin.php`) 可以被正确加载 ✓
|
|
||||||
- 旧子目录控制器无法被 PluginsService 找到(类路径不匹配)✗
|
|
||||||
- [x] **P1-T3**: 实施修复 — 创建 `admin/Admin.php`(注意:不是根目录,是 admin/ 子目录)
|
|
||||||
- `admin/Admin.php` 路径 → 类名 `\app\plugins\vr_ticket\admin\Admin` ✓
|
|
||||||
- 方法使用 camelCase:`SeatTemplateList()`, `TicketList()` 等
|
|
||||||
- sidebar URL 必须用 camelCase:`pluginsaction=seatTemplateList`
|
|
||||||
- 修复 plugin.json sidebar URL:改为 `/plugins/vr_ticket/admin/seatTemplateList` 格式
|
|
||||||
- [ ] **P1-T4**: 验证修复后路由能否正常渲染(需实际访问 URL 截图)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## P2 — 侧栏插件名乱码问题
|
|
||||||
|
|
||||||
### 已知现象
|
|
||||||
- 侧栏显示:`VR票务`(应为 `VR票务`)
|
|
||||||
- 这是 UTF-8 字符串被当作 Latin1/ISO-8859-1 解码的结果
|
|
||||||
- 乱码规律:`票` (E7 A5 8A) → Latin1 解码为 `票务`
|
|
||||||
|
|
||||||
### 乱码根因假设
|
|
||||||
| 假设 | 可能性 | 验证方式 |
|
|
||||||
|------|--------|----------|
|
|
||||||
| 数据库 `vrt_power` 表 name 字段 latin1 编码存储 | 高 | 检查 MySQL `SHOW CREATE TABLE vrt_power` |
|
|
||||||
| 数据库连接 charset 不匹配 | 中 | 检查 ShopXO 数据库配置 charset |
|
|
||||||
| plugin.json 编码问题 | 低 | plugin.json 已是正确 UTF-8 |
|
|
||||||
|
|
||||||
### 任务清单
|
|
||||||
|
|
||||||
- [ ] **P2-T1**: 确认乱码根因 — 检查 vrt_power 表结构
|
|
||||||
- `SHOW CREATE TABLE vrt_power`
|
|
||||||
- `SHOW FULL COLUMNS FROM vrt_power`
|
|
||||||
- 确认 name 字段 charset 和 collate
|
|
||||||
- [ ] **P2-T2**: 如果是数据库 latin1 问题 — 修复方案
|
|
||||||
- 方案A:ALTER TABLE 转换 latin1 → utf8mb4
|
|
||||||
- 方案B:MySQL CONVERT/CAST 函数读取时转换
|
|
||||||
- 方案C:PHP 层以 latin1 读出再转 utf8
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 视图路径问题(Round 5 根因确认 + 修复)
|
|
||||||
|
|
||||||
### 根因(BackendArchitect 分析)
|
|
||||||
ThinkPHP 5 视图路径解析规则:
|
|
||||||
1. 相对路径(如 `'seat_template/list'`):相对于**控制器 namespace 对应的默认视图目录**
|
|
||||||
2. namespace `app\plugins\vr_ticket\admin` → 默认视图目录 `app/plugins/vr_ticket/admin/view/`
|
|
||||||
3. 实际文件在 `app/admin/view/default/plugins/view/vr_ticket/admin/view/` ← 路径不匹配!
|
|
||||||
|
|
||||||
### 实际文件位置
|
|
||||||
```
|
|
||||||
app/admin/view/default/plugins/view/vr_ticket/admin/view/
|
|
||||||
├── seat_template/
|
|
||||||
│ ├── list.html
|
|
||||||
│ └── save.html
|
|
||||||
├── ticket/
|
|
||||||
│ ├── list.html
|
|
||||||
│ └── detail.html
|
|
||||||
├── venue/
|
|
||||||
│ ├── list.html
|
|
||||||
│ └── save.html
|
|
||||||
├── verifier/
|
|
||||||
│ ├── list.html
|
|
||||||
│ └── save.html
|
|
||||||
└── verification/
|
|
||||||
└── list.html
|
|
||||||
```
|
|
||||||
|
|
||||||
### 修复方案
|
|
||||||
ThinkPHP 5 以 `/` 开头的视图路径为**绝对路径**,相对于配置的视图根目录(`app/admin/view/default/`)解析。
|
|
||||||
|
|
||||||
修复前(错误):
|
|
||||||
```php
|
|
||||||
return view('seat_template/list', $data); // 解析到 app/plugins/vr_ticket/admin/view/ ← 不存在
|
|
||||||
```
|
|
||||||
|
|
||||||
修复后(正确):
|
|
||||||
```php
|
|
||||||
return view('/plugins/view/vr_ticket/admin/view/seat_template/list', $data);
|
|
||||||
// → app/admin/view/default/plugins/view/vr_ticket/admin/view/seat_template/list.html ✓
|
|
||||||
```
|
|
||||||
|
|
||||||
**所有 9 个 view() 调用已全部修复为绝对路径格式。**
|
|
||||||
|
|
||||||
### Vrticket.php 的参考价值
|
|
||||||
`shopxo/app/admin/controller/Vrticket.php` 使用 `MyView('../../../plugins/vr_ticket/admin/' . $template)` 手动处理路径。
|
|
||||||
Admin.php 使用 ThinkPHP `view()` 函数,以 `/` 开头则由 ThinkPHP 自动解析到 `app/admin/view/default/`。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 阶段划分
|
|
||||||
|
|
||||||
| 阶段 | 内容 | 负责 |
|
|
||||||
|------|------|------|
|
|
||||||
| **Round 1(规划)** | 分析根因,制定修复方案 | FrontendDev |
|
|
||||||
| **Round 2(执行)** | 实施 admin/Admin.php + plugin.json 修复 | FrontendDev |
|
|
||||||
| **Round 3(综合)** | 合并到 main,完整验证 | 所有成员 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 依赖关系
|
|
||||||
|
|
||||||
- P1-T3 和 P1-T4 需要实际访问 URL 验证(无法在 CLI 环境截图)
|
|
||||||
- P2-T1 需要连接数据库检查编码
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 交付物
|
|
||||||
|
|
||||||
1. 修复后的 `shopxo/app/plugins/vr_ticket/admin/Admin.php`(路由正确)
|
|
||||||
2. 修复后的 `shopxo/app/plugins/vr_ticket/plugin.json`(sidebar URL 使用 camelCase)
|
|
||||||
3. 乱码问题修复(需数据库层修复)
|
|
||||||
|
|
||||||
## 状态
|
|
||||||
|
|
||||||
| 任务 | 状态 | 备注 |
|
|
||||||
|------|------|------|
|
|
||||||
| P1-T1 | [Done] | PluginsService 路由机制已分析 |
|
|
||||||
| P1-T2 | [Done] | admin/Admin.php 模式正确 |
|
|
||||||
| P1-T3 | [Done] | admin/Admin.php 已创建 + plugin.json 已修复 |
|
|
||||||
| P1-T4 | [Pending] | 需实际访问 URL 截图验证 |
|
|
||||||
| P2-T1 | [Done] | 根因:plugins.name 字段 Latin1 存储 |
|
|
||||||
| P2-T2 | [Done] | SQL 修复脚本见 docs/SQL_FIX_garbled_plugin_name.md |
|
|
||||||
| P1-视图路径 | [Done] | 所有 9 个 view() 改为绝对路径 `/plugins/view/vr_ticket/admin/view/...` |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## BackendArchitect Round 5 实现
|
|
||||||
|
|
||||||
### 交付物
|
|
||||||
1. ✅ `shopxo/app/plugins/vr_ticket/admin/Admin.php` — 9 个 view() 调用全部改为 `/plugins/view/vr_ticket/admin/view/...` 绝对路径
|
|
||||||
2. ✅ `docs/SQL_FIX_garbled_plugin_name.md` — 乱码修复 SQL 脚本
|
|
||||||
3. ✅ `plan.md` — 更新根因分析
|
|
||||||
|
|
||||||
### P1 乱码 DB 根因(最终确认)
|
|
||||||
- `plugins.name` 字段 = `VR票务`(Latin1 解码的 UTF-8 字节)
|
|
||||||
- 安装时 `plugin.json` 的 `title: "VR票务"` 被以 Latin1 编码存入 MySQL
|
|
||||||
- 读取时 MySQL 连接 charset 是 utf8mb4,所以 Latin1 字节被错误解码为乱码
|
|
||||||
- **修复**:执行 `UPDATE sx_plugins SET name = 'VR票务' WHERE plugins = 'vr_ticket'`
|
|
||||||
|
|
||||||
### 乱码字节分析
|
|
||||||
`票` UTF-8: `E7 A5 8A` → Latin1 解读为: `票务`
|
|
||||||
`务` UTF-8: `E5 8A B1` → (in `VR票务` combined string)
|
|
||||||
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## SecurityEngineer Round 5 补充
|
|
||||||
|
|
||||||
### 关键发现:VenueList() 方法缺失(Critical Bug)
|
|
||||||
plugin.json sidebar URL `/plugins/vr_ticket/admin/venueList` 链接到 `VenueList()` 方法,但 admin/Admin.php 中该方法不存在 → 点击"场馆配置"菜单会导致 500 错误。
|
|
||||||
|
|
||||||
**已修复**:在 admin/Admin.php 中添加:
|
|
||||||
- `VenueList()` — 场馆列表(含 v3.0 seat_map 解析)
|
|
||||||
- `VenueSave()` — 场馆创建/编辑(含 v3.0 JSON 构建和验证)
|
|
||||||
- `VenueDelete()` — 场馆软删除(含审计日志)
|
|
||||||
- `countSeatsV2()` — v2 格式(数组)座位计数辅助方法
|
|
||||||
|
|
||||||
### 安全审计结论
|
|
||||||
|
|
||||||
| 安全项 | 风险等级 | 结论 |
|
|
||||||
|--------|----------|------|
|
|
||||||
| SQL 注入 | LOW | 所有查询使用 ThinkPHP query builder + 参数绑定 |
|
|
||||||
| XSS | LOW | ThinkPHP 模板引擎自动转义,无 `\|raw` 输出 |
|
|
||||||
| 路径遍历 | LOW | 所有视图路径为硬编码方法名,无用户输入 |
|
|
||||||
| CSRF | MEDIUM | ShopXO 框架级缺失,插件层面无法单独修复 |
|
|
||||||
| 数据编码(P1乱码)| LOW | DB latin1 存储导致乱码,非安全漏洞 |
|
|
||||||
|
|
||||||
### P1 乱码 DB 修复 SQL
|
|
||||||
|
|
||||||
```sql
|
|
||||||
-- 1. 诊断
|
|
||||||
SELECT id, name, title, LENGTH(name), HEX(name) FROM shx_plugins WHERE name LIKE '%vr%';
|
|
||||||
|
|
||||||
-- 2. 修复 plugins 表
|
|
||||||
UPDATE shx_plugins SET name = 'vr_ticket', title = 'VR票务' WHERE name = 'vr_ticket';
|
|
||||||
|
|
||||||
-- 3. 修复 vrt_power 表(如果存在乱码)
|
|
||||||
SELECT id, name, LENGTH(name), HEX(name) FROM vrt_power WHERE name LIKE '%票%';
|
|
||||||
UPDATE vrt_power SET name = 'VR票务' WHERE HEX(name) LIKE '%E7A58A%';
|
|
||||||
```
|
|
||||||
|
|
||||||
详细安全分析见:`reviews/SecurityEngineer-round5-review.md`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## SecurityEngineer Round 6 — 文档评审
|
|
||||||
|
|
||||||
> 任务:对 Phase 2 相关 3 份文档进行评审
|
|
||||||
> 规则:只读文档,不读代码文件;不修改任何文件;不 push
|
|
||||||
|
|
||||||
### 待评审文档
|
|
||||||
|
|
||||||
| # | 文档 | 评审重点 |
|
|
||||||
|---|------|---------|
|
|
||||||
| D1 | `docs/14_TEMPLATE_RENDER_INVESTIGATION.md` | 数据流表名是否正确、Think驱动结论是否有效、解决方案是否合理 |
|
|
||||||
| D2 | `docs/PHASE2_PLAN.md` | 任务优先级、风险评估、决策点清晰度 |
|
|
||||||
| D3 | `docs/DEVELOPMENT_LOG.md`(第十一+十二章) | 事实准确性、时间线一致性、遗漏的关键信息 |
|
|
||||||
|
|
||||||
### 评审维度(每份文档覆盖)
|
|
||||||
|
|
||||||
1. **准确性** — 技术描述、数据流、表名是否正确
|
|
||||||
2. **完整性** — 是否遗漏边界条件/安全考量/依赖项
|
|
||||||
3. **可操作性** — 下一步行动是否清晰可执行
|
|
||||||
4. **一致性** — 各文档之间表名/文件路径/状态描述是否一致
|
|
||||||
5. **误导风险** — 是否有表述易让接手者误解
|
|
||||||
|
|
||||||
### 任务清单
|
|
||||||
|
|
||||||
- [ ] **D1-T1**: 评审 `docs/14_TEMPLATE_RENDER_INVESTIGATION.md` → 输出到 `reviews/SecurityEngineer-on-docs-review.md`
|
|
||||||
- [ ] **D1-T2**: 评审 `docs/PHASE2_PLAN.md` → 追加到 `reviews/SecurityEngineer-on-docs-review.md`
|
|
||||||
- [ ] **D1-T3**: 评审 `docs/DEVELOPMENT_LOG.md`(第十一+十二章)→ 追加到 `reviews/SecurityEngineer-on-docs-review.md`
|
|
||||||
- [ ] **D1-T4**: 综合建议 + Top 3 最需要修正的问题 → 追加到 `reviews/SecurityEngineer-on-docs-review.md`
|
|
||||||
- [ ] **D1-T5**: 合并评审结果到 `reviews/SecurityEngineer-on-docs-review.md` 并提交到 main
|
|
||||||
|
|
||||||
### 交付物
|
|
||||||
|
|
||||||
`reviews/SecurityEngineer-on-docs-review.md` — 三份文档各自的评分(5维度)+ 总体评价 + Top 3 修正建议
|
|
||||||
|
|
||||||
### 状态
|
|
||||||
|
|
||||||
- [ ] D1-T1 `[Claimed: council/SecurityEngineer]`
|
|
||||||
- [ ] D1-T2 `[Claimed: council/SecurityEngineer]`
|
|
||||||
- [ ] D1-T3 `[Claimed: council/SecurityEngineer]`
|
|
||||||
- [ ] D1-T4 `[Claimed: council/SecurityEngineer]`
|
|
||||||
- [ ] D1-T5 `[Claimed: council/SecurityEngineer]`
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue