--- title: 嵌套路由 panelId 缺少 productId 归属校验(IDOR) date: 2026-02-15 module: panel-nested-routes problem_type: security_issue severity: critical symptoms: - /api/products/[id]/panels/[panelId] 与 /holes 子路由按 panelId 直接读写 - 未校验 panel.productId 与 URL 中 productId 一致 root_cause: 路由层默认信任路径参数,未建立资源归属约束 resolution_type: code_fix status: active confidence: high tags: [security, idor, route, panel, product] related_patterns: [SEC-PANEL-BOUNDARY-001] --- ## 现象与影响 攻击者可构造“任意 productId + 目标 panelId”请求,在嵌套路由下越权读取或修改其他产品下的板件/孔位。 ## 修复动作 1. 在 `panel.service.ts` 新增 `assertPanelBelongsToProduct(panelId, productId)`。 2. 在 `products/[id]/panels/[panelId]/route.ts` 与 `products/[id]/panels/[panelId]/holes/route.ts` 所有读写入口统一先做归属校验。 3. `panel.service.findById` 增加 `canViewProduct` 权限护栏,并将板件详情 GET 改为认证访问。 ## 验证 - `npm run type-check -- --pretty false` 通过 - `npm test -- tests/lib/cad-panel-linking.test.ts --runInBand` 通过 - `npm test -- tests/api/auth-me.test.ts --runInBand` 通过 ## 预防策略 - 所有形如 `/products/:productId/.../:resourceId` 的接口,必须执行“resource -> productId 与路径一致”校验。 - 归属校验与权限校验都应在 Service 层有可复用方法,Route 只负责调用。