从 Simple-FR 拆出 Platform.Server 并重命名为 MiGu.Server;frontends 源码与构建脚本迁入本仓库。地图监控在 projection/cars 失败或为空时回退 reflection 车辆列表;Simple 仓库已移除旧 Platform.Server。 Co-authored-by: Cursor <cursoragent@cursor.com>
12 KiB
12 KiB
本周代码复审报告(2026-05-23 ~ 2026-05-29)
用途:对本周全部改动(含已提交)的一次复审,聚焦后端 C# 安全性与正确性。 仓库:
E:\Work\Core\Simple-FR\Simple分支:dev_simpleLite基线:d8d4d3c(2026-05-21)→ HEAD:1412bf0(含一次合并远程的 merge) 本文档为本地工作记录,默认不纳入版本库。
1. 范围与方法
- 本周累计:37 commit,277 文件,+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-05(writableViaApi 403)/ ISSUE-06(GET 只读)/ ISSUE-08(Envelope 统一),均经
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-02(config/ai-completion.json 入 gitignore) 两项低成本加固;RV-01/RV-03 视风险排期。功能性模块与前端建议在子代理可用后做一轮专项复审。
6. 本轮处理与补充发现(会话 65 续)
6.1 已修复(按「修复 RV-04 + P2 加固项」)
- RV-01(SSRF):
AiCompletionService.GenerateMapInternalAsync发请求前校验 endpoint —— 仅允许 http/https(挡file://等异常 scheme),指向内网/回环时记审计日志但不阻断(兼容自建 LLM)。新增IsPrivateOrLoopbackHost。 - RV-02(密钥入库):
.gitignore增**/config/ai-completion.json。 - RV-03(信息泄露):上游 LLM 非 2xx 时原始响应仅进日志(截断 500 字符),前端只返回状态码 + “详见日志”。
- RV-04(loopback):经核实已可配置(
PlatformOptions.allowLoopbackBypass,ProjectionWebHost.cs:51已接线),无需改代码;已在MiGu.Server/README.md安全须知补充「生产建议allowLoopbackBypass=false」。
6.2 补充深审结论(质量良好)
- 实时流
ProjectionStreamModule/AlarmStreamService:每订阅者一把SemaphoreSlim+finally清理 CTS/锁 + 断连移除;删除车辆时清LastAlarmByCar防膨胀;反射FieldInfo缓存。仅 P2(SSEDispose与 fire-and-forgetBroadcast的竞态已被catch (ObjectDisposedException)吸收;AlarmStreamTimer 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 错误。 |