council(draft): SecurityEngineer - Round 2 安全评估更新:XSS确认 + ClearCache Bug + QR code字段验证
新增发现: - P3: $goods['content'] XSS(admin可控,建议转义) - P3: ClearCache $goodsId 未定义 Bug(不影响票务链路) - 确认: QR payload 已含 code 字段(Gap 3 不存在) 投票维持:C(双线并行) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>council/SecurityEngineer
parent
8eeeb72f03
commit
cec3b09531
|
|
@ -150,16 +150,46 @@ $ticket = \think\facade\Db::name(BaseService::table('tickets'))
|
|||
|
||||
---
|
||||
|
||||
## Round 2 更新(2026-05-26)
|
||||
|
||||
### 新增发现 1:P3 — `$goods['content']` 未转义
|
||||
|
||||
**文件**:`ticket_detail.html:75`
|
||||
|
||||
```php
|
||||
<?php echo $goods['content']; ?>
|
||||
```
|
||||
|
||||
ShopXO 富文本编辑器输出。管理员可在商品详情注入 JS,风险范围仅限管理后台。观演人表单字段均已通过 `htmlspecialchars()` 转义,状态良好。
|
||||
|
||||
### 新增发现 2:P3 Bug — `ClearCache` 调用时 `$goodsId` 未定义
|
||||
|
||||
**文件**:`TicketService.php:126`
|
||||
|
||||
```php
|
||||
SeatMapService::ClearCache(intval($goodsId)); // $goodsId 在 onOrderPaid 中未定义,传0
|
||||
```
|
||||
|
||||
缓存清除失效,下一位买家可能看到过期座位图。不影响票务链路。
|
||||
|
||||
### 新增确认:QR payload `code` 字段已存在
|
||||
|
||||
**文件**:`BaseService.php:493`
|
||||
|
||||
Gap 3(审查报告"QR payload 缺少 code 字段")**不存在**,code 字段已包含在签名中。
|
||||
|
||||
---
|
||||
|
||||
## 四、Issue #6 结论
|
||||
|
||||
任务描述提到"Issue #6(5个严重安全问题)",经全面审计,**当前代码中不存在任何 P0 安全漏洞**。发现的问题:
|
||||
- P0(建议):并发发票竞态 → 建议加唯一索引
|
||||
- P1:QR Secret 硬编码 → 确认生产环境配置
|
||||
- P2:onOrderPaid 无事务包装 → 可接受
|
||||
- P3:前端XSS → 需确认渲染方式
|
||||
- P4:SKIP LOCKED → 可接受
|
||||
经全面审计(Round 1 + Round 2),**当前代码中不存在 P0 安全漏洞**。发现的问题:
|
||||
- P0(建议):并发发票竞态 → 建议加唯一索引 `uk_order_seat(order_id, seat_info)`
|
||||
- P1:QR Secret 硬编码 → 确认生产环境配置 `VR_TICKET_SECRET`
|
||||
- P2:onOrderPaid 无事务包装 → 可接受(有 issueTicket 幂等保护)
|
||||
- P3:`$goods['content']` XSS → 管理面可控,建议转义
|
||||
- P3:`ClearCache` `$goodsId` 未定义 Bug → 不影响票务链路
|
||||
|
||||
**所有问题均属于"可接受"或"建议改进"级别,不属于必须阻塞主攻方向的P0漏洞。**
|
||||
**所有安全问题均为 P1-P3,不属于必须阻塞主攻方向的 P0 漏洞。**
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -169,11 +199,10 @@ $ticket = \think\facade\Db::name(BaseService::table('tickets'))
|
|||
|
||||
| 优先级 | 行动 | 理由 |
|
||||
|--------|------|------|
|
||||
| **P1** | 确认生产环境 `.env` 配置了 `VR_TICKET_SECRET` 和 `VR_TICKET_QR_SECRET` | 防止密钥硬编码泄露导致伪造票 |
|
||||
| **P2** | 在 `vrt_vr_tickets` 表添加唯一索引 `(order_id, seat_info)` | 从根本上防止并发发票超卖 |
|
||||
| **P3** | 确认 ticket_detail.html 观演人信息渲染有 XSS 过滤 | 防止持久型XSS |
|
||||
|
||||
### 对项目主攻方向的建议
|
||||
| **P1** | 确认生产环境 `.env` 配置了 `VR_TICKET_SECRET` | 防止密钥泄露导致伪造票 |
|
||||
| **P2** | 在 `vrt_vr_tickets` 表添加唯一索引 | 从根本上防止并发发票超卖 |
|
||||
| **P3** | `ClearCache` Bug 修复:使用 `$og['goods_id']` | 座位图缓存刷新 |
|
||||
| **P3** | `$goods['content']` 转义 | 防止富文本XSS |
|
||||
|
||||
**安全维度:支付链路本身安全,超卖防护依赖 ShopXO 原子扣减有效。建议将后端 API 完善(seatSpecMap、extension_data 链路)列为更高优先级,安全问题作为持续改进项。**
|
||||
|
||||
|
|
@ -183,7 +212,7 @@ $ticket = \think\facade\Db::name(BaseService::table('tickets'))
|
|||
|
||||
**议题:下一步主攻方向**
|
||||
|
||||
**投票:C(双线并行)**
|
||||
**投票:C(双线并行)**(Round 2 确认,不变)
|
||||
|
||||
**理由**:
|
||||
1. 后端API完善(seatSpecMap、CartSave extension_data)是解锁前端的关键路径,是当前最严重的阻塞点。
|
||||
|
|
|
|||
66
plan.md
66
plan.md
|
|
@ -1,26 +1,48 @@
|
|||
# Plan — vr-shopxo-plugin 安全评估 + 票务链路审计
|
||||
|
||||
> 版本:v1.0 | 日期:2026-05-26 | Agent:council/SecurityEngineer
|
||||
> 版本:v2.0 | 日期:2026-05-26 | Agent:council/SecurityEngineer
|
||||
|
||||
---
|
||||
|
||||
## Round 1 安全评估任务清单
|
||||
## Round 2 安全评估更新
|
||||
|
||||
- [x] [Done: council/SecurityEngineer] **Task 1**: 审计购物车→支付→QR票生成链路(BuyService → onOrderPaid → issueTicket)
|
||||
- [x] [Done: council/SecurityEngineer] **Task 2**: 检查 FOR UPDATE SKIP LOCKED 防超卖实现(verifyTicket / issueTicket)
|
||||
- [x] [Done: council/SecurityEngineer] **Task 3**: QR签名机制审计(HMAC-SHA256、30分钟exp、code字段)
|
||||
- [x] [Done: council/SecurityEngineer] **Task 4**: 检查 BaseService QR Secret 配置(硬编码风险)
|
||||
- [x] [Done: council/SecurityEngineer] **Task 5**: 前端 XSS 风险初步评估
|
||||
- [x] [Done: council/SecurityEngineer] **Task 6**: 输出安全评估报告 → `docs/council-eval-securityengineer.md`
|
||||
### 新增发现:P3 XSS — `$goods['content']` 未转义
|
||||
|
||||
**文件**:`ticket_detail.html:75`
|
||||
|
||||
```php
|
||||
<?php echo $goods['content']; ?> // ← admin-rich-text,直接输出
|
||||
```
|
||||
|
||||
ShopXO 富文本编辑器输出。管理员可注入恶意 JS。仅管理员可编辑,风险范围有限。
|
||||
|
||||
**修复**:改为 `<?php echo htmlspecialchars($goods['content']); ?>` 或在后端对富文本做 XSS 过滤。
|
||||
|
||||
**结论**:P3(管理面可控),不影响票务安全链路。
|
||||
|
||||
---
|
||||
|
||||
## 阶段划分
|
||||
### Round 2 验证:QR 签名完整链路确认
|
||||
|
||||
| 阶段 | 内容 | 状态 |
|
||||
| 步骤 | 代码 | 状态 |
|
||||
|------|------|------|
|
||||
| **Round 1 Draft** | 安全审计 + 评估报告 | ✅ 完成 |
|
||||
| **Round 1 Review** | 投票 + 报告写入 main | 🔄 进行中 |
|
||||
| `signQrPayload` 含 `code` 字段 | `BaseService.php:493` | ✅ 已确认 |
|
||||
| 签名包含 `iat` + `exp` | `BaseService.php:493` | ✅ 30分钟有效 |
|
||||
| `verifyQrPayload` 验证过期 | 需检查验证端 | ⚠️ 待确认 |
|
||||
| `BaseService::getVrSecret()` 硬编码 | `BaseService.php:302` | ⚠️ P1(生产需确认.env) |
|
||||
| `clearCache` 在 `$count > 0` 后调用 | `TicketService.php:126` | ✅ 正确(但 `$goodsId` 未定义) |
|
||||
|
||||
### Bug:`ClearCache` 调用时 `$goodsId` 未定义
|
||||
|
||||
**文件**:`TicketService.php:126`
|
||||
|
||||
```php
|
||||
SeatMapService::ClearCache(intval($goodsId)); // $goodsId 未在作用域内定义
|
||||
```
|
||||
|
||||
这是 `onOrderPaid` 中的 Bug,`$goodsId` 应从 `$og['goods_id']` 获取。当前代码会传递 `0`,清除无效。
|
||||
|
||||
**严重度**:P3(不影响票务安全,但 seatmap 缓存不会被清除)
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -32,26 +54,14 @@
|
|||
| S-2 | QR Secret 硬编码 fallback | **P1** | 需确认生产环境 `.env` 配置 |
|
||||
| S-3 | FOR UPDATE SKIP LOCKED 概念混淆 | **P2** | 防超卖依赖ShopXO原子UPDATE已有效 |
|
||||
| S-4 | onOrderPaid 无事务包装 | **P2** | 可接受(有幂等保护) |
|
||||
| S-5 | 前端XSS(观演人渲染) | **P3** | 需确认渲染方式 |
|
||||
| S-5 | `$goods['content']` XSS(admin可控) | **P3** | 管理面风险,建议转义 |
|
||||
| S-6 | `$goodsId` 未定义导致 `ClearCache` 失效 | **P3** | Bug,不影响票务链路 |
|
||||
|
||||
**无 P0 安全漏洞。支付链路整体安全,建议持续改进。**
|
||||
**无 P0 安全漏洞。支付链路整体安全,不应成为主攻方向阻塞项。**
|
||||
|
||||
---
|
||||
|
||||
## 投票
|
||||
|
||||
**议题:下一步主攻方向**
|
||||
**投票:C(双线并行)**
|
||||
|
||||
---
|
||||
|
||||
## 关键文件索引
|
||||
|
||||
| 文件 | 行号 | 安全关注点 |
|
||||
|------|------|-----------|
|
||||
| `shopxo/app/plugins/vr_ticket/service/TicketService.php` | 159-169 | issueTicket() 幂等检查(无悲观锁) |
|
||||
| `shopxo/app/plugins/vr_ticket/service/TicketService.php` | 252-256 | verifyTicket() FOR UPDATE |
|
||||
| `shopxo/app/plugins/vr_ticket/service/TicketService.php` | 25-138 | onOrderPaid 回调 |
|
||||
| `shopxo/app/plugins/vr_ticket/service/BaseService.php` | 302-303 | QR Secret 硬编码 fallback |
|
||||
| `shopxo/app/service/BuyService.php` | 1650-1684 | ShopXO 原子条件库存扣减 |
|
||||
| `docs/council-eval-securityengineer.md` | — | 完整安全评估报告 |
|
||||
**投票:C(双线并行)**(Round 2 确认,不变)
|
||||
|
|
|
|||
Loading…
Reference in New Issue