Files
Migu2.0/Doc/CODE_REVIEW_WEEK_2026-05-29.md
T
zhaowei.huangandCursor 42978930ca feat: 迁入 MiGu.Server、平台前端与车辆列表 reflection 回退
从 Simple-FR 拆出 Platform.Server 并重命名为 MiGu.Server;frontends 源码与构建脚本迁入本仓库。地图监控在 projection/cars 失败或为空时回退 reflection 车辆列表;Simple 仓库已移除旧 Platform.Server。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-29 18:16:34 +08:00

134 lines
12 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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-05-23 ~ 2026-05-29
> **用途**:对本周全部改动(含已提交)的一次复审,聚焦后端 C# 安全性与正确性。
> **仓库**`E:\Work\Core\Simple-FR\Simple` **分支**`dev_simpleLite`
> **基线**`d8d4d3c`2026-05-21)→ **HEAD**`1412bf0`(含一次合并远程的 merge
> **本文档为本地工作记录,默认不纳入版本库。**
---
## 1. 范围与方法
- 本周累计:**37 commit277 文件,+32461 / 5740 行**;其中后端 C# **96 文件 / +15302 行**为审核核心。
- `MiGu.Server/wwwroot/assets`(占 dirstat 28%)为前端构建产物,忽略。
- 说明:本轮原计划用 5 个并行子代理分模块审核,但因账户账单(unpaid invoice)子代理不可用,改为**人工聚焦后端安全关键面**深度审核;功能性大文件(录制/流/UI/Workspace)与前端做轻量或留待后续。
### 已深度审阅
| 文件 | 关注点 | 结论 |
|------|--------|------|
| `MiGu.Server/Launcher/SimpleLiteLauncher.cs` | 命令注入/进程生命周期/JobObject | 良好 |
| `SimpleLite/Web/AiCompletionService.cs` | SSRF/密钥/Prompt 注入/并发 | 见 RV-01~03 |
| `SimpleLite/PluginManager.cs` | 任意 DLL 加载/RCE/并发 | 良好(入口受限) |
| `SimpleLite/Web/AiConfigController.cs` | 密钥脱敏 | 良好 |
| `SimpleLite/Web/InternalAuthModule.cs` | 8222 鉴权 | 见 RV-04 |
| `SimpleLite/Web/ReflectionApiController.cs`(本会话已改部分) | writableViaApi/只读/Envelope | 已修 ISSUE-05/06/08 |
| `SimpleLite/Persistence/Repositories/CarRepository.cs` | 反序列化白名单 | 已修 ISSUE-10 |
### 鉴权链确认(关键前提)
- `InternalAuthModule`(AR-1/AR-2)统一前置守护所有 `/projection/*`reflection / map-edit / persistence / ai-config / stream)。
- MiGu.Server 侧 Controller 已加 `[Authorize]`AR-4)。
- **结论**:AI 生图、插件 reload、字段写入等敏感入口**不可被未认证外部直接触达**——这把多处原本可能的高危项降级为 P2 加固建议。
---
## 2. 发现清单(按严重度)
### P1 — 建议处理(视部署环境)
#### RV-04 — InternalAuthModule loopback 默认无条件放行
- **文件**`SimpleLite/Web/InternalAuthModule.cs:79-80``AllowLoopback` 默认 `true`
- **现象**:本机回环(127.0.0.1/::1/IPv4-mapped)请求**不校验 token 直接放行**。
- **风险**:单机可信环境无碍;但在**多租户/共享主机**或存在可打到 `127.0.0.1:8222` 的 SSRF 时,本机任意进程即可接管调度内核(execute [MethodMember] / patch 字段 / reload plugin)。
- **建议**:生产(尤其共享主机)通过配置将 `AllowLoopback=false`,强制依赖 `X-Platform-Internal-Token`;并在部署文档标注。代码已预留开关,无需改逻辑,仅需配置 + 文档。
### P2 — 加固建议
#### RV-01 — AiCompletion endpoint 无 SSRF 白名单
- **文件**`SimpleLite/Web/AiCompletionService.cs:191-197`
- **现象**`cfg.Endpoint`(管理员经 ai-config 表单可配任意 URL)被服务端 `SharedClient.SendAsync` 直接请求,并携带 `Authorization: Bearer <apiKey>`
- **风险**:已认证管理员可让服务器向任意(含内网)URL 发带密钥请求 → SSRF / 密钥外泄到非预期端点。
- **建议**:对 `Endpoint` 做 scheme 限制(仅 https)+ host 白名单/黑名单(禁内网段),或显式告警「endpoint 指向内网」。
#### RV-02 — apiKey 明文存盘且 config/ 未被 gitignore
- **文件**`SimpleLite/Web/AiCompletionService.cs:71-99``CWD/config/ai-completion.json` 明文读写)
- **现象**`apiKey` 明文落盘;`.gitignore` 未覆盖 `config/` 或该文件(已核查无匹配规则)。
- **风险**:误 `git add config/` 或随包分发会泄露 LLM 密钥。
- **建议**`.gitignore` 增加 `**/config/ai-completion.json`(或运行时 `config/`);考虑落盘前对 apiKey 做 DPAPI/对称加密。注:GET 已脱敏(`AiConfigController.MaskApiKey`),此项仅针对磁盘文件。
#### RV-03 — AiCompletion 把 LLM 原始响应回抛前端
- **文件**`SimpleLite/Web/AiCompletionService.cs:199-200``throw ... LLM HTTP {status}: {raw}`
- **现象**:上游非 2xx 时把 `raw` 响应体原样抛出,经 `MapEditApiController` 返回前端。
- **风险**:信息泄露(上游错误细节/内部 endpoint),低概率含敏感片段。
- **建议**:仅记日志保留 `raw`,对前端返回精简错误码与通用提示。
#### RV-05 — 登录阻塞至 Readiness 超时(同 ISSUE-01
- **文件**`MiGu.Server/Controllers/AuthController.cs:111` + `SimpleLiteLauncher.WaitForProjectionReady`
- **现状**:已通过 `SimpleLiteOptions.ReadinessTimeoutMs`(可配,0=立即返回)缓解;真正的「fire-and-forget + 前端轮询」留待迭代。
---
## 3. 已确认良好(无需改动)
- **SimpleLiteLauncher**`displayMode``NormalizeDisplayMode` 归一为固定枚举(web / web+local),命令行无注入面;`_opts.Arguments` 来自受信 appsettings;进程 `Exited` 事件用 `ReferenceEquals(_proc, proc)` 防误清;JobObject 资源用 `AllocHGlobal/FreeHGlobal` 配对释放。
- **PluginManager**`reload` 入口(`/reflection/plugins/reload`)只**重扫固定 `./plugins` 目录**,不接受任意路径参数 → 无「任意路径 DLL 加载」漏洞;`Load`/`Unload` 全程加锁(修复历史并发覆盖 bug);collectible ALC + WeakReference + GC best-effort 卸载。
- **AiConfigController**GET 脱敏 `apiKey``***`+后4位);POST 对脱敏占位保留旧值,避免被覆盖清空。
- **InternalAuthModule**token 校验用 `CryptographicOperations.FixedTimeEquals` 防 timing;未配置 token 时一律拒绝远程(仅 loopback 可入)。
- **AiCompletionService 并发**:静态 `SharedClient`(避免 socket exhaustion+ `Timeout.Infinite` + `CancellationTokenSource` 控制单次超时;`BoundsContext``AsyncLocal` 跨 await 保持并 `try/finally` 清理。
- **本会话修复**:ISSUE-10(反序列化白名单)/ ISSUE-05writableViaApi 403/ ISSUE-06GET 只读)/ ISSUE-08Envelope 统一),均经 `dotnet build SimpleLite` 验证 0 错误。
---
## 4. 未深审(建议后续专项)
| 区域 | 文件(本周新增/大改) | 建议关注 |
|------|----------------------|----------|
| 录制/回放 | `SimulationRecorder` `PlaybackController` `RecordingFileIO` `SimulationPlayer` `SchedulerProbe` | 文件句柄/内存映射释放、帧索引边界 |
| 实时流 | `ProjectionStreamModule` `AlarmStreamService` | SSE 连接泄漏/重连/背压 |
| 持久化 | `SceneRepository` `ScriptRepository` `MissionRepository` `PersistenceWorker` `PersistenceBootstrap` | EF DbContext 生命周期、并发、事务 |
| 交互/渲染 | `WorkspaceSceneInput` `CurveControlPointDragService` `SimpleSceneRenderer` `ComposerDockPanel` `SimpleUI` | 线程竞态、事件/定时器泄漏 |
| 前端 | `simple-platform-vue/**` | 鉴权守卫、契约一致、XSS、mock 开关(子代理不可用,本轮未审) |
---
## 5. 结论
本周后端改动建立在会话 53 的安全基线(AR-1~AR-6)之上,**鉴权链完整、未见新增高危漏洞**。建议优先处理 **RV-04(生产关 loopback****RV-02config/ai-completion.json 入 gitignore** 两项低成本加固;RV-01/RV-03 视风险排期。功能性模块与前端建议在子代理可用后做一轮专项复审。
---
## 6. 本轮处理与补充发现(会话 65 续)
### 6.1 已修复(按「修复 RV-04 + P2 加固项」)
- **RV-01SSRF**`AiCompletionService.GenerateMapInternalAsync` 发请求前校验 endpoint —— 仅允许 http/https(挡 `file://` 等异常 scheme),指向内网/回环时记审计日志但不阻断(兼容自建 LLM)。新增 `IsPrivateOrLoopbackHost`
- **RV-02(密钥入库)**`.gitignore``**/config/ai-completion.json`
- **RV-03(信息泄露)**:上游 LLM 非 2xx 时原始响应仅进日志(截断 500 字符),前端只返回状态码 + “详见日志”。
- **RV-04loopback**:经核实**已可配置**`PlatformOptions.allowLoopbackBypass``ProjectionWebHost.cs:51` 已接线),无需改代码;已在 `MiGu.Server/README.md` 安全须知补充「生产建议 `allowLoopbackBypass=false`」。
### 6.2 补充深审结论(质量良好)
- **实时流** `ProjectionStreamModule` / `AlarmStreamService`:每订阅者一把 `SemaphoreSlim` + `finally` 清理 CTS/锁 + 断连移除;删除车辆时清 `LastAlarmByCar` 防膨胀;反射 `FieldInfo` 缓存。仅 P2SSE `Dispose` 与 fire-and-forget `Broadcast` 的竞态已被 `catch (ObjectDisposedException)` 吸收;`AlarmStream` Timer Tick 极端慢时可能重入,`ConcurrentDictionary` 保证安全)。
- **录制文件 IO** `RecordingFileIO``compressedLen` ≤ 64MB 校验、`ReadExact` 截断检测、GZip 流 `using` 释放、`ScanIndex` 损坏帧停止。仅 P2(解压后大小无上限,GZip 炸弹理论风险;录像为本地受信文件,实际影响小)。
### 6.3 补充发现并修复
- **RV-06(已预防性修复,2026-05-29** `PersistenceWorker.FlushUpsert`/`FlushDelete` 原在 `ctx.SaveChanges()` / `tx.Commit()` **之前**就调用 `SetHash`/`RemoveHash`,若事务随后回滚,`_lastWrittenHash` 已记录该 hash → 后续 `ShouldSkipWrite` 跳过重写 → 该变更(尤其低频状态如 Mission/Script)可能永久不落库。`AUDIT.md` 的 PB-1~PB-5 未覆盖此项。虽 `Startup.cs:72-74` 已整体下线持久化(worker 不运行),仍按要求预防性修复:
- `FlushUpsert`/`FlushDelete` 改为把 hash 变更累积到局部 `hashOps``hash==null` 表示移除),不再直接改字典;
- 仅当 `SaveChanges()` + `tx.Commit()` 成功后才由新增的 `ApplyHashOps``_hashLock` 内原子应用;回滚 / 异常路径不应用,保留「下次仍需写入」语义;
- 删除不再使用的 `SetHash`/`RemoveHash``ReadLints` 验证 0 错误(完整 `dotnet build` 仍受 §6.4 weaver 环境阻塞)。
### 6.4 编译验证说明(受阻于织入工具链环境问题)
- 修复仅触及 `SimpleLite/Web/AiCompletionService.cs`(标准 C#`Uri.TryCreate` / `IPAddress` / 字符串操作)。
- **首次** `dotnet build SimpleLite/SimpleLite.csproj`(本会话早段)**0 错误**成功,`LessokajiWeaver` 在线织入完整跑过(约 51s,日志 `Online compilation finished`)。
- **本次复验**SimpleCore 报 20 个 `CS0246/CS0616/CS0641`,全部是 `LessokajiWeaver` 在线织入临时项目(`obj/MaxKeeper_tmp`)应提供的类型缺失(`I18N`/`MethodMember`/`MaxValueKeeper`/`KeepMaxMod`/`ReplaceWithCompileInfo`);`--no-incremental` 全量重建仍 7s 即失败,未进入在线织入。**错误列表无任何 SimpleLite 文件**。
- 判定:**织入工具链在线服务/状态不可用的环境问题,非本次代码问题**。建议在 VS2022 正常环境、或 `tools\setenv.ps1` 恢复 deps 且 weaver 在线服务可用后复验本次 AI 服务改动。
### 6.5 未完成(建议后续专项)
- `Workspace` / `UI` / `Rendering`、前端全量:本轮因并行子代理不可用(账户账单)未深审,建议子代理恢复后补一轮。
---
## 修订记录
| 日期 | 说明 |
|------|------|
| 2026-05-29 | 初版:会话 65 本周复审(聚焦后端安全关键面;子代理因账单不可用,人工聚焦审核) |
| 2026-05-29 | 续:修复 RV-01/02/03 + RV-04 文档;补深审(流/文件良好、PersistenceWorker 发现 RV-06);编译复验受阻于 LessokajiWeaver 在线织入环境问题(与改动无关)。 |
| 2026-05-29 | 续:按要求预防性修复 RV-06(hash 延迟到事务 Commit 后由 ApplyHashOps 原子应用);本会话全部 5 个改动文件 ReadLints 0 错误。 |