Files
update-client/docs/configuration-and-security.md
T

7.9 KiB

配置与安全

配置模型

配置分为两个拥有不同所有者的类别:

  1. 产品配置是在配置时选择和验证的。它被嵌入到运行时中,并在二进制文件构建完成后变为只读。
  2. 机器状态在产品安装过程中会发生变化。它由原生系统范围的后端存储,并且永远不会重新定义产品策略。

此拆分将可编辑的 app_config.json 从已安装的信任路径中移除。

配置时源选择

自动选择使用以下顺序:

  1. config/config.json,当该文件存在时。
  2. config/app_config.example.json,否则。

集成构建可能会通过 UPDATE_CLIENT_PRODUCT_CONFIG_FILE 传递一个确切的文件;该显式输入具有优先权,必须由配置输出报告。清除缓存变量可恢复自动选择。

config/config.json 是一个本地或发布流水线输入。它必须保持未跟踪状态。示例是一个可构建的开发备用方案,而不是生产密钥存储。

配置必须在所选文件格式错误、缺少必需值、值类型错误或路径违反运行时布局协议时失败。所选的 JSON 文件将被规范化为生成的资源并嵌入到 qrc 中。源 JSON 文件和生成的中间文件不得安装。

产品配置

产品配置包括定义二进制文件被允许运行的产品的值:

  • application ID 和显示名称;
  • 发布渠道和客户端协议;
  • API 基础 URL 和非特权客户端令牌;
  • 启动票验证材料;
  • 可执行角色名称和安装布局;
  • 更新临时目录策略;
  • 请求和健康检查超时;以及
  • 目标平台和架构。

所选的源也包含一个 initial_state 对象。它仅提供以下可变键的首次运行默认值。它不会将这些键变为不可变策略,之后的运行时更改仍保留在本地状态存储中。

发布者必须在未跟踪的 config/config.json 中提供已签发且非空的 initial_state.license_key。示例配置中的空值只支持开发构建;父级 package_installer 会拒绝缺失、空值或明显占位符。该值会作为初始状态嵌入二进制文件,并在系统级授权状态缺失或为空时由 Launcher 写入;已有的非空机器授权不会被构建默认值覆盖。授权不会作为可编辑的安装目录 JSON 交付。

这些值可能在不同构建之间有所不同,但安装的文件不得覆盖它们。在可执行文件旁边放置名为 app_config.jsonclient.iniconfig.json 的文件,不是受支持的运行时覆盖。

可执行文件路径必须是相对的、规范化的,并且限定在批准的安装根目录内。它们不得包含遍历段,也不得指向产品外部的任意可执行文件。

可变机器状态

机器状态包括:

  • 当前安装的版本;
  • 许可证注册值;
  • 安装和设备标识符;
  • 迁移完成标记;
  • 单调更新或策略状态未包含在已签名的缓存中。

Qt 客户端在系统范围内使用原生后端存储这些值,并禁用回退查找。在 Windows 上,这是机器级别的注册表位置。其他平台使用等效的原生系统位置。当前逻辑命名空间是 SimCAE/UpdateClient,产品状态如下 products/<app-id>/<channel>/state/,因此所有更新客户端进程都访问同一个存储,而不会混合产品或频道。

发布启动必须具有读取和更新此状态所需的平台权限。未能持久化所需状态会导致启动错误;不得触发回退到可执行目录 JSON。

已签名的策略、清单和设备凭证缓存,在其格式需要时可以使用经批准的数据文件。此类文件是运行时缓存,而非产品配置,其签名在使用前必须进行验证。

版本和发布边界

已安装的版本是本地状态。服务器版本、通道、策略和发布清单是通过服务器工作流程显式发布的。本地构建、Git 版本、头信息值或安装程序文件名不得自动发布或授权服务器发布。

客户端只能在提交并验证的更新事务的一部分中报告其已安装的版本并将其向前推进。

安全属性

嵌入数据不是机密

qrc 可防止对侧边 JSON 文件进行随意编辑。它不会阻止机器管理员进行二进制检查或修改。因此,客户端中嵌入的值不得包含服务器发布或管理权限。

API 客户端令牌和启动票据材料是客户端凭证。服务器端点仍必须对每个操作进行身份验证,并独立授权设备、许可证、频道和版本。

原生状态不是信任根

系统范围的原生存储提高了所有权和访问控制,尤其是在系统安装中。管理员仍然可以对其进行修改。本地版本、许可证文本或迁移标志不能替代服务器验证。

签名的服务器数据具有权威性

服务器私钥从不会离开服务器。客户端仅接收公开验证材料。客户端会验证所有适用的签名工件,包括:

  • 版本策略;
  • 完整文件清单;
  • 设备凭证;和
  • 离线更新元数据,如支持。

签名的有效负载标识其使用的算法和密钥 ID,并采用确定性的序列化方式。密钥轮换可能会保留当前和立即前一个公钥,以便在受控的迁移窗口期内进行过渡。未知密钥或无效签名将关闭失败。

设备身份不等于用户登录

设备发行将应用程序、频道、安装、设备和许可证绑定在一起。它不会创建终端用户会话,也不会授予对管理发布接口的访问权限。

启动票证作用范围

一次性票券绑定预期的应用、设备、版本和较短的有效期。应用会一次性消耗该票券。票券验证阻止普通直接启动,但不会使策略或完整性检查变得可选。

完整性与回滚

更新程序可能仅下载更改的文件,但受保护的安装会针对完整的签名清单进行验证。在文件操作前会检查路径。先前版本会在候选版本健康状态确认之前进行备份,并在另一次更新前恢复中断的事务。

公开验证材料

公钥不是秘密。它们可以作为显式的公共运行时资产嵌入或安装,前提是包拥有其来源,并且客户端不会在没有其他可信锚点的情况下接受任意替换。私钥和服务器管理凭证绝不能进入此仓库或安装程序。

发布包规则

已安装的树中不得包含:

  • app_config.json;
  • client.ini;
  • source config.json;
  • app_config.example.json;
  • license 或 device state 从构建机器复制过来; 或
  • 生成的产品配置中间件。

该包必须包含验证服务器合约所需的二进制文件和公共资源。父目标 package_installer 拥有这些安装规则。

必要的篡改检查

发布验证必须证明:

  1. 添加或更改侧边车 JSON 不会改变嵌入式应用程序 ID、频道、端点、可执行文件名称或票证行为。
  2. 更改本地状态无法伪造有效的服务器签名或获取发布权限。
  3. 更改受保护的二进制文件或库会被清单验证检测到。
  4. 重放或编辑启动票证将被拒绝。
  5. 用较旧的已签名序列替换策略或清单会被反回滚状态拒绝。
  6. 候选启动失败会导致回滚,而不是版本状态的前进。

操作指南

  • 请将特定版本的 config/config.json 保留在版本控制之外,并通过受控的构建环境提供。
  • 每次发布都要在该文件中配置已签发的 initial_state.license_key;不要把真实授权值写入示例、文档或版本控制。
  • 限制对发布构建输入的访问,但不要将客户端侧的值描述为不可提取的秘密。
  • 通过明确的发布流程轮换服务器签名密钥和客户端令牌。
  • 在原生后端和权限边界处诊断状态写入失败。不要使安装目录广泛可写。
  • 将更改的端点、频道、可执行文件名称或启动票据密钥视为新的二进制配置,需要重新构建和包验证。