Files
Migu2.0/Doc/CODE_REVIEW_WEEK_2026-05-29.md
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

12 KiB
Raw Permalink Blame History

本周代码复审报告(2026-05-23 ~ 2026-05-29

用途:对本周全部改动(含已提交)的一次复审,聚焦后端 C# 安全性与正确性。 仓库E:\Work\Core\Simple-FR\Simple 分支dev_simpleLite 基线d8d4d3c2026-05-21)→ HEAD1412bf0(含一次合并远程的 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-80AllowLoopback 默认 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-99CWD/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-200throw ... 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. 已确认良好(无需改动)

  • SimpleLiteLauncherdisplayModeNormalizeDisplayMode 归一为固定枚举(web / web+local),命令行无注入面;_opts.Arguments 来自受信 appsettings;进程 Exited 事件用 ReferenceEquals(_proc, proc) 防误清;JobObject 资源用 AllocHGlobal/FreeHGlobal 配对释放。
  • PluginManagerreload 入口(/reflection/plugins/reload)只重扫固定 ./plugins 目录,不接受任意路径参数 → 无「任意路径 DLL 加载」漏洞;Load/Unload 全程加锁(修复历史并发覆盖 bug);collectible ALC + WeakReference + GC best-effort 卸载。
  • AiConfigControllerGET 脱敏 apiKey***+后4位);POST 对脱敏占位保留旧值,避免被覆盖清空。
  • InternalAuthModuletoken 校验用 CryptographicOperations.FixedTimeEquals 防 timing;未配置 token 时一律拒绝远程(仅 loopback 可入)。
  • AiCompletionService 并发:静态 SharedClient(避免 socket exhaustion+ Timeout.Infinite + CancellationTokenSource 控制单次超时;BoundsContextAsyncLocal 跨 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(生产关 loopbackRV-02config/ai-completion.json 入 gitignore 两项低成本加固;RV-01/RV-03 视风险排期。功能性模块与前端建议在子代理可用后做一轮专项复审。


6. 本轮处理与补充发现(会话 65 续)

6.1 已修复(按「修复 RV-04 + P2 加固项」)

  • RV-01SSRFAiCompletionService.GenerateMapInternalAsync 发请求前校验 endpoint —— 仅允许 http/https(挡 file:// 等异常 scheme),指向内网/回环时记审计日志但不阻断(兼容自建 LLM)。新增 IsPrivateOrLoopbackHost
  • RV-02(密钥入库).gitignore**/config/ai-completion.json
  • RV-03(信息泄露):上游 LLM 非 2xx 时原始响应仅进日志(截断 500 字符),前端只返回状态码 + “详见日志”。
  • RV-04loopback:经核实已可配置PlatformOptions.allowLoopbackBypassProjectionWebHost.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 RecordingFileIOcompressedLen ≤ 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 变更累积到局部 hashOpshash==null 表示移除),不再直接改字典;
    • 仅当 SaveChanges() + tx.Commit() 成功后才由新增的 ApplyHashOps_hashLock 内原子应用;回滚 / 异常路径不应用,保留「下次仍需写入」语义;
    • 删除不再使用的 SetHash/RemoveHashReadLints 验证 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 错误。