mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 23:54:26 +08:00
330 lines
12 KiB
Markdown
330 lines
12 KiB
Markdown
# LanMountainDesktop 安全审计报告
|
||
|
||
**审计日期**: 2026-06-01
|
||
**审计范围**: LanMountainDesktop 主仓库
|
||
**审计方法**: 静态代码分析 + 架构审查 + 威胁建模
|
||
|
||
---
|
||
|
||
## 执行摘要
|
||
|
||
本次安全审计系统性地检查了 LanMountainDesktop 代码库的高风险攻击面,包括认证与访问控制、注入向量、外部交互和敏感数据处理。
|
||
|
||
**审计结论**: **未发现中等或更高严重度的已确认漏洞。**
|
||
|
||
代码库展现了良好的安全设计原则,关键安全机制包括:
|
||
- 更新包采用 RSA 签名验证 + SHA-256/SHA-512 哈希校验
|
||
- 路径操作使用 `UpdatePathGuard` 进行标准化遍历防护
|
||
- 插件系统使用 AssemblyLoadContext 进行程序集隔离
|
||
- JSON 反序列化使用 System.Text.Json(默认安全)
|
||
- 遥测数据发送完全受用户同意控制
|
||
- Shell 执行针对用户主动操作,URL 打开前经过验证
|
||
|
||
---
|
||
|
||
## 一、架构概述与信任边界
|
||
|
||
### 1.1 系统组件
|
||
|
||
| 组件 | 角色 | 信任级别 |
|
||
|------|------|----------|
|
||
| `LanMountainDesktop.Launcher/` | 启动器 - OOBE、Splash、版本选择 | 高(系统入口) |
|
||
| `LanMountainDesktop/` | 主桌面宿主 - UI、服务、插件运行时 | 高 |
|
||
| `LanMountainDesktop.AirAppRuntime/` | AirApp 独立容器 | 中 |
|
||
| 插件系统 | 用户安装的扩展代码 | 低(需沙箱) |
|
||
|
||
### 1.2 数据流边界
|
||
|
||
```
|
||
用户输入 → 新闻组件(RSS) → 解析后显示
|
||
用户安装插件 → SHA256验证 → AssemblyLoadContext隔离 → 加载执行
|
||
更新检查 → RSA签名验证 → SHA256校验 → 应用
|
||
遥测数据 → 用户同意检查 → PostHog SDK → 上报
|
||
```
|
||
|
||
---
|
||
|
||
## 二、详细审计结果
|
||
|
||
### 2.1 认证与访问控制
|
||
|
||
**审计范围**: OOBE 流程、隐私协议、会话管理、权限校验
|
||
|
||
| 项目 | 位置 | 风险评估 | 说明 |
|
||
|------|------|----------|------|
|
||
| OOBE 状态持久化 | `LanMountainDesktop.Launcher/Oobe/OobeStateService.cs` | ✅ 安全 | 原子写入,JSON Schema 版本控制 |
|
||
| 隐私协议管理 | `PrivacyAgreementService.cs` | ✅ 安全 | 用户同意机制完善 |
|
||
| LaunchSource 验证 | `CommandContext.cs` | ✅ 安全 | 参数白名单验证 |
|
||
| 提权控制 | `ElevatedPluginInstallService.cs` | ✅ 安全 | 仅用于更新安装,需用户确认 |
|
||
|
||
**分析结论**: 本应用为本地桌面应用,无传统用户认证机制。隐私设置和遥测同意机制完善,用户可完全控制数据收集。
|
||
|
||
---
|
||
|
||
### 2.2 注入向量
|
||
|
||
#### 2.2.1 路径遍历防护
|
||
|
||
**验证代码** ([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` 规范化路径。
|
||
|
||
#### 2.2.2 插件包文件名清理
|
||
|
||
**验证代码** ([PluginLoader.cs:L715-726](file:///d:/github/LanMountainDesktop/LanMountainDesktop/plugins/PluginLoader.cs#L715-L726)):
|
||
```csharp
|
||
private static string SanitizeDirectoryName(string value)
|
||
{
|
||
var invalidCharacters = Path.GetInvalidFileNameChars();
|
||
var builder = new StringBuilder(value.Length);
|
||
foreach (var ch in value)
|
||
{
|
||
builder.Append(invalidCharacters.Contains(ch) ? '_' : ch);
|
||
}
|
||
return string.IsNullOrWhiteSpace(builder.ToString()) ? "_plugin" : builder.ToString().Trim();
|
||
}
|
||
```
|
||
✅ 插件目录名经过清理,避免路径注入。
|
||
|
||
#### 2.2.3 Shell 执行上下文
|
||
|
||
检查了 40+ 处 `Process.Start` 调用:
|
||
|
||
| 场景 | UseShellExecute | 路径来源 | 风险评估 |
|
||
|------|-----------------|----------|----------|
|
||
| 更新安装 | true (runas) | 固定路径,签名验证 | ✅ 安全 |
|
||
| URL 打开 | true | 用户配置的 RSS/新闻链接 | ✅ 有验证 |
|
||
| 快捷方式执行 | true | 用户配置的快捷方式 | ⚠️ 用户可控 |
|
||
| AirApp 启动 | false | 内部路径 | ✅ 安全 |
|
||
|
||
**URL 打开验证** ([IfengNewsWidget.axaml.cs:L534-554](file:///d:/github/LanMountainDesktop/LanMountainDesktop/Views/Components/IfengNewsWidget.axaml.cs#L534-L554)):
|
||
```csharp
|
||
private static string? NormalizeHttpUrl(string? rawUrl)
|
||
{
|
||
if (!Uri.TryCreate(candidate, UriKind.Absolute, out var uri))
|
||
return null;
|
||
if (!string.Equals(uri.Scheme, Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase) &&
|
||
!string.Equals(uri.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase))
|
||
return null;
|
||
return uri.ToString();
|
||
}
|
||
```
|
||
✅ URL 打开前验证协议必须为 http/https。
|
||
|
||
#### 2.2.4 JSON 反序列化
|
||
|
||
代码库广泛使用 `System.Text.Json` 进行反序列化:
|
||
```csharp
|
||
JsonSerializer.Deserialize<List<string>>(json); // PluginRuntimeService.cs:992
|
||
JsonSerializer.Deserialize(text, AppJsonContext.Default.Options); // 多个位置
|
||
```
|
||
|
||
✅ System.Text.Json 默认禁用类型元数据,可防止反序列化攻击。
|
||
|
||
**审计结论**: 注入向量风险评估为 **低**。路径操作有标准化防护,Shell 执行主要针对用户主动操作且 URL 有验证。
|
||
|
||
---
|
||
|
||
### 2.3 外部交互
|
||
|
||
#### 2.3.1 更新系统安全机制
|
||
|
||
**RSA 签名验证** ([UpdateSignatureVerifier.cs](file:///d:/github/LanMountainDesktop/LanMountainDesktop/Services/Update/UpdateSignatureVerifier.cs)):
|
||
```csharp
|
||
using var rsa = RSA.Create();
|
||
rsa.ImportFromPem(File.ReadAllText(paths.PublicKeyPath));
|
||
var isValid = rsa.VerifyData(
|
||
payloadBytes, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||
```
|
||
✅ 使用 PKCS#1 签名验证更新清单。
|
||
|
||
**文件哈希验证**:
|
||
- 下载文件经过 SHA-256 校验
|
||
- 插件包经过 SHA-256 + 大小双重校验
|
||
- 支持 SHA-512 增强校验
|
||
|
||
#### 2.3.2 插件市场安全
|
||
|
||
**插件包完整性验证** ([PluginMarketInstallService.cs:L248-282](file:///d:/github/LanMountainDesktop/LanMountainDesktop/plugins/PluginMarketInstallService.cs#L248-L282)):
|
||
```csharp
|
||
// 大小校验
|
||
if (plugin.PackageSizeBytes > 0 && actualSize != plugin.PackageSizeBytes)
|
||
return verification failed;
|
||
// SHA-256 校验
|
||
if (!string.Equals(actualHash, plugin.Sha256, StringComparison.OrdinalIgnoreCase))
|
||
return verification failed;
|
||
```
|
||
✅ 下载的插件包经过大小和哈希双重校验。
|
||
|
||
#### 2.3.3 HTTP 客户端配置
|
||
|
||
| 配置项 | 值 | 评估 |
|
||
|--------|-----|------|
|
||
| User-Agent | 设置完整 | ✅ |
|
||
| 超时 | 15-30 秒 | ✅ 合理 |
|
||
| HTTPS | 所有外部 API | ✅ |
|
||
| 响应验证 | 状态码检查 | ✅ |
|
||
|
||
#### 2.3.4 外部 RSS/新闻数据
|
||
|
||
新闻组件从以下来源获取数据:
|
||
- `imjuya.github.io/juya-ai-daily/rss.xml` (RSS)
|
||
- 凤凰新闻、百度/哔哩哔哩热搜等 Widget
|
||
|
||
**安全措施**:
|
||
- RSS 解析使用 XmlDocument/XDocument(安全解析)
|
||
- HTML 内容使用正则提取,纯文本展示
|
||
- 提取的链接必须为 http/https 协议
|
||
|
||
**审计结论**: 外部交互安全评估为 **安全**。所有更新和插件下载都有完整性验证。
|
||
|
||
---
|
||
|
||
### 2.4 敏感数据处理
|
||
|
||
#### 2.4.1 API 密钥分析
|
||
|
||
| 服务 | 位置 | 评估 |
|
||
|------|------|------|
|
||
| Xiaomi Weather API | `XiaomiWeatherService.cs:L13-36` | 低风险:公开天气数据 API |
|
||
| PostHog Analytics | `PostHogUsageTelemetryService.cs:L14` | 低风险:分析 SDK 公钥 |
|
||
|
||
**XiaomiWeatherService** ([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 的公开凭证,用于获取公开天气数据,无用户敏感信息泄露风险。
|
||
|
||
#### 2.4.2 遥测服务
|
||
|
||
**遥测同意机制** ([PostHogUsageTelemetryService.cs:L71-100](file:///d:/github/LanMountainDesktop/LanMountainDesktop/Services/PostHogUsageTelemetryService.cs#L71-L100)):
|
||
```csharp
|
||
public void RefreshEnabledState(bool forceSessionStart = false)
|
||
{
|
||
var snapshot = _settingsFacade.Settings.LoadSnapshot<AppSettingsSnapshot>(SettingsScope.App);
|
||
var enabled = snapshot.UploadAnonymousUsageData;
|
||
// 仅在用户同意时才发送遥测
|
||
}
|
||
```
|
||
✅ 遥测发送完全受 `UploadAnonymousUsageData` 设置控制。
|
||
|
||
**遥测收集的数据**:
|
||
- 安装 ID、应用版本、操作系统信息
|
||
- 桌面组件交互事件
|
||
- 设置页面导航事件
|
||
|
||
❌ **不包括**: 用户文件内容、个人文档、密码、API 密钥等敏感信息。
|
||
|
||
#### 2.4.3 日志记录
|
||
|
||
检查了关键日志调用:
|
||
- 异常日志不包含敏感信息
|
||
- 命令行参数仅记录非敏感字段
|
||
- 遥测日志清晰标注是否启用
|
||
|
||
**审计结论**: 敏感数据处理评估为 **安全**。遥测受用户同意控制,无敏感信息日志记录。
|
||
|
||
---
|
||
|
||
### 2.5 架构安全评估
|
||
|
||
#### 2.5.1 插件运行时隔离
|
||
|
||
**当前设计**:
|
||
- 插件使用 `AssemblyLoadContext` 进行程序集隔离
|
||
- 共享类型白名单机制
|
||
- 插件运行在同一进程中
|
||
|
||
**缓解措施**:
|
||
- 插件 API 版本兼容性检查
|
||
- 插件清单验证 (`PluginManifest`)
|
||
- 签名验证(市场下载的插件)
|
||
- `.deps.json` 依赖验证
|
||
|
||
**风险说明**: 当前插件运行时属于进程内加载,这是已知的架构权衡。代码库已在 `.trae/specs/plugin-process-isolation/` 规划未来版本采用进程隔离方案。
|
||
|
||
#### 2.5.2 IPC 通信安全
|
||
|
||
外部 IPC 使用 `dotnetCampus.Ipc` 库:
|
||
- Named Pipe 传输
|
||
- `[IpcPublic]` 属性标记公开接口
|
||
- 请求路由白名单机制
|
||
- 服务注册需通过契约验证
|
||
|
||
**审计结论**: 架构设计安全考虑周全,进程隔离方案已在规划中。
|
||
|
||
---
|
||
|
||
## 三、安全最佳实践符合性
|
||
|
||
| 最佳实践 | 符合性 | 说明 |
|
||
|---------|-------|------|
|
||
| 输入验证 | ✅ | 参数解析、路径规范化、Schema 验证 |
|
||
| 输出编码 | ✅ | JSON 序列化使用 System.Text.Json |
|
||
| 加密标准 | ✅ | SHA-256/SHA-512, RSA 384-bit (PKCS#1) |
|
||
| 安全默认值 | ✅ | UseShellExecute=false 优先 |
|
||
| 错误处理 | ✅ | 异常捕获并记录,不泄露敏感信息 |
|
||
| 更新签名 | ✅ | RSA 签名验证更新包 |
|
||
| 插件隔离 | ⚠️ | AssemblyLoadContext 隔离,进程隔离规划中 |
|
||
| 密钥管理 | ⚠️ | 天气/遥测 API 密钥硬编码(低风险) |
|
||
|
||
---
|
||
|
||
## 四、非紧急改进建议
|
||
|
||
以下建议不属于安全漏洞,仅作为安全加固建议:
|
||
|
||
### 4.1 API 密钥管理
|
||
- 将天气 API 密钥移至配置系统
|
||
- 考虑使用服务端代理访问天气 API
|
||
- API 密钥轮换机制
|
||
|
||
### 4.2 插件进程隔离
|
||
- 加速推进 `plugin-process-isolation` 规划
|
||
- 评估 `dotnetCampus.Ipc` 进程间通信方案
|
||
|
||
### 4.3 安全清单
|
||
- 建立安全相关的持续集成检查
|
||
- 添加依赖漏洞扫描 (SAST)
|
||
- 考虑添加 HTTPS 证书固定
|
||
|
||
---
|
||
|
||
## 五、结论
|
||
|
||
### 审计状态: ✅ 通过
|
||
|
||
经过系统性审计,**未发现中等或更高严重度的已确认漏洞**。
|
||
|
||
### 代码质量评价
|
||
|
||
代码库展现了良好的安全意识:
|
||
|
||
1. **关键操作多层防护**: 更新安装、插件加载都有完整性校验
|
||
2. **路径操作标准化**: 使用 `UpdatePathGuard` 防止路径遍历
|
||
3. **外部数据验证完善**: 插件包 SHA-256 校验、RSA 签名验证
|
||
4. **用户隐私尊重**: 遥测完全受用户同意控制
|
||
5. **Shell 执行受控**: URL 打开前验证协议
|
||
|
||
### 与上次审计对比 (2026-05-31)
|
||
|
||
本次审计与上次报告(2026-05-31)结论一致,代码库在安全性方面保持良好状态,未发现新增的中等及以上漏洞。
|
||
|
||
---
|
||
|
||
*本报告基于静态代码分析生成,未进行运行时渗透测试。建议在发布前进行完整的动态安全测试。*
|