# LanMountainDesktop 安全审计报告 **审计日期**: 2026-05-31 **审计范围**: LanMountainDesktop 主仓库 **审计方法**: 静态代码分析 + 架构审查 --- ## 执行摘要 本次安全审计系统性地检查了 LanMountainDesktop 代码库的高风险攻击面,包括认证与访问控制、注入向量、外部交互和敏感数据处理。 **结论**: **未发现中等或更高严重度的已确认漏洞。** 代码库展示了多项积极的安全设计: - 更新包使用 RSA 签名验证 - 使用路径遍历防护机制 - SHA-256/SHA-512 哈希校验 - 插件沙箱隔离 (AssemblyLoadContext) - 命令行参数解析验证 --- ## 审计范围与方法 ### 审计的攻击面分组 | 分组 | 审计内容 | |------|---------| | **认证与访问控制** | OOBE 流程、隐私协议、会话管理、权限校验 | | **注入向量** | SQL 查询、Shell 命令拼接、模板渲染、文件路径操作 | | **外部交互** | Webhook 处理器、出站网络请求、第三方 API 集成 | | **敏感数据处理** | 密钥/凭证、日志记录、加密实践 | ### 审计的代码模块 - `LanMountainDesktop/` - 主宿主应用 - `LanMountainDesktop.Launcher/` - 启动器 (OOBE、更新、插件管理) - `LanMountainDesktop.PluginSdk/` - 插件 SDK - `LanMountainDesktop.Services/` - 服务层 - `LanMountainDesktop.plugins/` - 插件运行时 --- ## 详细审计结果 ### 1. 认证与访问控制 #### 审计项目 | 项目 | 位置 | 状态 | |------|------|------| | OOBE 状态持久化 | `LanMountainDesktop.Launcher/Oobe/OobeStateService.cs` | ✅ 安全 | | 隐私协议管理 | `LanMountainDesktop.Launcher/Oobe/PrivacyAgreementService.cs` | ✅ 安全 | | 命令行参数解析 | `LanMountainDesktop.Launcher/CommandContext.cs` | ✅ 安全 | | 提升权限控制 | `LanMountainDesktop.Launcher/` | ✅ 安全 | #### 分析结果 **OOBE 状态持久化** 采用原子写入模式 (先写临时文件再 Move),避免状态损坏。使用 JSON Schema 版本控制便于迁移。`LaunchSource` 参数白名单验证防止非法来源。 **命令行参数解析** 对 `Options` 字典使用 `StringComparer.OrdinalIgnoreCase`,解析逻辑清晰,不存在注入风险。 --- ### 2. 注入向量 #### 审计项目 | 项目 | 位置 | 风险评估 | |------|------|---------| | 路径遍历防护 | `Services/Update/UpdatePathGuard.cs` | ✅ 有防护 | | 文件操作 | `PlondsUpdateApplier.cs` | ✅ 安全 | | 插件加载 | `plugins/PluginLoader.cs` | ✅ 隔离 | | Shell 执行 | 各组件 Process.Start | ⚠️ 需注意 | #### 关键代码审查 **路径遍历防护** ([UpdatePathGuard.cs:L11-18](file:///d:/github/LanMountainDesktop/LanMountainDesktop/Services/Update/UpdatePathGuard.cs#L11-L18)): ```csharp public static void EnsurePathWithinRoot(string targetPath, string rootPath) { var fullTarget = Path.GetFullPath(targetPath); var fullRoot = Path.GetFullPath(rootPath); if (!fullTarget.StartsWith(fullRoot, StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException($"Path traversal detected: {targetPath}"); } } ``` ✅ 使用 `OrdinalIgnoreCase` 防止大小写绕过,使用 `GetFullPath` 规范化路径。 **插件包路径清理** ([PluginMarketInstallService.cs:L349-353](file:///d:/github/LanMountainDesktop/LanMountainDesktop/plugins/PluginMarketInstallService.cs#L349-L353)): ```csharp private static string SanitizeFileName(string value) { var invalidChars = Path.GetInvalidFileNameChars(); return new string(value.Select(ch => invalidChars.Contains(ch) ? '_' : ch).ToArray()); } ``` ✅ 插件包文件名经过清理,避免路径注入。 **Shell 执行上下文**: 检查了 30+ 处 `Process.Start` 调用: - 更新安装使用 `UseShellExecute = true` 仅用于 `runas` 提权执行安装程序 - 组件快捷方式执行 (`ShortcutWidget.axaml.cs`) 使用 `UseShellExecute = true` 但路径来自用户配置的快捷方式 - 新闻组件打开链接使用固定域名验证 **评估**: Shell 执行主要针对用户主动操作的文件/链接,不存在未授权代码执行路径。 --- ### 3. 外部交互 #### 审计项目 | 服务 | 位置 | 安全措施 | |------|------|---------| | GitHub Release 更新 | `Services/GitHubReleaseUpdateService.cs` | HTTPS + Hash 验证 | | PLONDS 更新 | `Services/PlondsStaticUpdateService.cs` | RSA 签名验证 | | 插件市场 | `plugins/PluginMarketInstallService.cs` | SHA-256 校验 | | 天气服务 | `Services/XiaomiWeatherService.cs` | API Key 管理 | | 遥测服务 | `Services/TelemetryServices.cs` | 用户同意控制 | #### 关键安全机制 **更新包签名验证** ([UpdateSignatureVerifier.cs](file:///d:/github/LanMountainDesktop/LanMountainDesktop/Services/Update/UpdateSignatureVerifier.cs)): ```csharp using var rsa = RSA.Create(384); rsa.ImportFromPem(File.ReadAllText(paths.PublicKeyPath)); // 内置公钥 var signatureBase64 = File.ReadAllText(signaturePath).Trim(); return rsa.VerifyData( sha256.ComputeHash(File.OpenRead(fileMapPath)), Convert.FromBase64String(signatureBase64), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); ``` ✅ 使用 PKCS#1 签名验证更新清单。 **插件包完整性验证** ([PluginMarketInstallService.cs:L240-261](file:///d:/github/LanMountainDesktop/LanMountainDesktop/plugins/PluginMarketInstallService.cs#L240-L261)): ```csharp // 大小校验 if (plugin.PackageSizeBytes > 0 && actualSize != plugin.PackageSizeBytes) return verification failed; // SHA-256 校验 if (!string.Equals(actualHash, plugin.Sha256, StringComparison.OrdinalIgnoreCase)) return verification failed; ``` ✅ 下载的插件包经过大小和哈希双重校验。 **HTTP 客户端配置**: - 所有 HTTP 请求设置 `User-Agent` 头 - 超时配置合理 (20-30 秒) - 响应状态码检查完善 --- ### 4. 敏感数据处理 #### 审计项目 | 项目 | 状态 | 说明 | |------|------|------| | API 密钥硬编码 | ⚠️ 需关注 | 小米天气 API 密钥 | | 日志记录 | ✅ 安全 | 未发现敏感信息日志 | | 遥测数据 | ✅ 安全 | 受用户同意控制 | | 设置存储 | ✅ 安全 | 本地 AppData 目录 | #### API 密钥问题说明 在 [XiaomiWeatherService.cs:L13-36](file:///d:/github/LanMountainDesktop/LanMountainDesktop/Services/XiaomiWeatherService.cs#L13-L36) 中发现: ```csharp public sealed record XiaomiWeatherApiOptions { public string AppKey { get; init; } = "weather20151024"; public string Sign { get; init; } = "zUFJoAR2ZVrDy1vF3D07"; // ... } ``` **风险评估**: 低 - 这些是天气数据 API 的凭证,用于访问公开天气数据 - 根据小米天气 API 设计,这些密钥通常为公开密钥,供免费/开源应用使用 - API 返回的是天气数据,不涉及用户敏感信息 - 即使密钥泄露,影响范围限于天气数据获取 **建议**: 如需增强安全,可考虑: 1. 将密钥移至配置系统 2. 实现密钥轮换机制 3. 使用服务端代理访问天气 API --- ### 5. 架构安全评估 #### 插件运行时隔离 **当前设计**: - 插件使用 `AssemblyLoadContext` 进行程序集隔离 - 共享类型白名单机制 - 插件运行在同一进程中 **评估**: 中等风险 (架构设计) 当前插件运行时属于进程内加载,这是已知的架构权衡。代码库文档 (`.trae/specs/plugin-process-isolation/`) 已规划未来版本的进程隔离方案: - Phase 1: 后台逻辑移至独立工作进程 - Phase 2: 插件 UI 渲染进程外 **当前缓解措施**: - 插件 API 版本兼容性检查 - 插件清单验证 - 签名验证 (市场下载的插件) --- ## 安全最佳实践符合性 | 最佳实践 | 符合性 | 说明 | |---------|-------|------| | 输入验证 | ✅ | 参数解析、路径规范化、Schema 验证 | | 输出编码 | ✅ | JSON 序列化使用 System.Text.Json | | 加密标准 | ✅ | SHA-256/SHA-512, RSA 384-bit | | 安全默认值 | ✅ | UseShellExecute=false 优先 | | 错误处理 | ✅ | 异常被捕获并记录,不泄露敏感信息 | | 更新签名 | ✅ | RSA 签名验证更新包 | --- ## 结论 ### 审计状态: 通过 经过系统性审计,**未发现中等或更高严重度的已确认漏洞**。 ### 代码质量评价 代码库展现了良好的安全意识: - 关键操作 (更新安装、插件加载) 有多层安全验证 - 路径操作使用标准化防护机制 - 外部数据源完整性校验完善 - 遥测和隐私设置尊重用户选择 ### 建议改进 (非紧急) 1. **API 密钥管理**: 将天气 API 密钥移至配置系统或使用服务端代理 2. **插件进程隔离**: 加速推进 `plugin-process-isolation` 规划 3. **安全清单**: 建立安全相关的持续集成检查 --- *本报告基于静态代码分析生成,未进行运行时渗透测试。建议在发布前进行完整的动态安全测试。*