Skip to content

Latest commit

 

History

History
135 lines (83 loc) · 14.3 KB

application-usage-sharing.md

File metadata and controls

135 lines (83 loc) · 14.3 KB

应用加固与签名使用情况分享

2026-09-18:本地实现与代码评审已完成,维护者确认按 1.4.0-beta.6 发布并升级远端服务。执行状态见发布任务与运维记录,不修改已发布的 Beta.5。

目标与准确性

了解哪些应用曾成功加固或独立签名,以及同一应用是否跨构建版本、跨发布周期复用工具。不以日活或每周打开作为主要价值指标。签名应用不能归入加固应用,整体覆盖以包名去重,不能直接相加两类应用数。

本功能是“默认参与、按应用退出的应用信息分享”,不是原有匿名统计,也不能称为用户主动加入。包名和名称可能涉及未公开项目,因此必须在设置页和版本说明中明确数据范围与默认行为。只在桌面 GUI 发生,不向 APK 壳添加上报,不为 CLI 增加默认联网。

统计只能证明客户端报告对应操作成功,不能证明 APK 正式发布、上线运行、商业采用或应用所有权。独立签名成功不能证明使用过本工具加固。同包名可能被不同项目使用;应用名称不能作为唯一键;改包名会被视作不同应用。未分享和上报失败的应用不在样本中,不能据此估计全部用户规模。

已确认的交互

加固页在开始按钮附近只显示一个复选框:

☑ 分享加固使用情况

签名页在开始按钮附近同样只显示一个复选框:

☑ 分享签名使用情况

两页共用同一包名偏好,不建立两个相互冲突的开关。任一页取消该应用分享,另一页下次空闲显示与新任务立即沿用取消;重新勾选则同样同步。执行中的页面仍显示其任务快照,后端发送前会检查最新取消状态。跨页取消会清除该包名全部未发送记录;重新开启不恢复此前已经放弃的记录。设置页明确说明此跨页生效范围。

不增加第二行说明、不放“查看发送内容”入口、不弹确认窗口、不挤占阶段进度区域。控件必须支持键盘、读屏和中英文文案。详细信息放设置页隐私说明,并在发布说明中告知行为变化。

选择 APK 后按可靠解析的包名读取本地偏好:

情况 行为
新包名、没有已保存记录 默认选中
同包名曾取消 保持取消
同包名升级版本、改名称、改文件路径 沿用选择
其他新包名 仍默认选中
用户重新勾选 保存为选中
元数据仍在解析或无法可靠解析包名 复选框未选中且禁用,不发送;不阻止原加固流程
任务执行中及结果快照页 冻结显示,不能修改本次选择
新任务快速切换 APK 丢弃旧解析响应,不能把前一个 APK 的选择套到新包名

退出偏好不得因重启、升级或清理统计缓存而重置,不按天失效,不自动淘汰取消记录。用户主动删除整个应用配置后属于新安装,无法保证恢复旧偏好。

独立于既有数据通道

通道 允许的数据 控制
匿名使用统计 随机安装标识、工具版本、功能及固定失败计数 原统计开关
安全错误报告 固定版本、阶段、错误码和受控环境 每份确认
本方案应用分享 应用包名、名称、版本、工具版本、操作类型、流程及成功日期 两页共用的当前包名分享选择

关闭匿名统计不等于关闭应用分享;这一区别必须写在设置页,不能把三个通道统一描述成“不采集包名”。本方案不发送匿名安装 UUID,不关联错误报告编号、任务 ID、账户或设备身份。不推断或宣传“匿名用户画像”。

建议设置页说明:应用分享由加固或签名页控制,新应用默认选中,同一包名在两页共用选择;发送应用名称、包名、应用版本、工具版本、操作类型、流程及成功日期,仅维护者可见,保留 180 天;不上传 APK、证书、密码或路径;取消停止该应用两类后续分享,不自动删除以前已经接收的数据。

数据协议

独立 POST /reports/application-usage,固定 schema_version=1,JSON 总长最多 8 KiB。所有字段必需,可空字段使用 null,禁止额外字段:

字段 来源与约束
submission_id 后端生成 UUID;同次重试不变
schema_version 整数 1
notice_version 整数 1,记录本次适用说明版本,不冒充主动同意证明
package_name 原始 Manifest 包名,大小写保留;1–255 个 ASCII 字符,点分段,每段以字母或下划线开头,其余为字母、数字或下划线;不符合即跳过分享,不拒绝加固
app_name 可空;直接 label 或安全解析的字符串资源;最多 256 个 Unicode 字符且最多 1 KiB UTF-8,无控制字符;不上传文件名作为兜底
app_version_code 可空;十进制字符串,范围 0 至 2^63−1,支持 versionCodeMajor 合成,避免 JavaScript 整数精度丢失
tool_version 后端编译版本,保留完整预发布后缀
operation 后端成功阶段决定:protect 或 sign
flow 后端任务类型决定:protect、protect_with_sign 或 sign
success_date 成功时冻结的 UTC 日期,服务端只接受过去 7 天至次日,容忍有限时钟误差

合法组合仅 (protect, protect)、(protect, protect_with_sign)、(sign, sign);禁止由前端任意声明,服务端拒绝其他组合。Beta.6 首轮实现使用完整第一版协议,不另升 schema。

不采集 versionName(可能是内部构建描述)、签名证书指纹、APK 哈希、图标、路径、设备标识、构建分支、完整日志、授权 APK 之外的文件。名称作为不可信纯文本存储和展示,绝不渲染为 HTML 或拼入 SQL。无法安全读取名称或版本时填 null;无法取得可靠包名则整条不发送。

元数据与任务绑定

复用 GUI 现有 manifest_inspect.rs 的只读二进制 Manifest 能力,补充包名、版本和直接 label,不使用正则猜包名或文件名。分享身份只接受结构与命名空间完整的二进制 Manifest:校验外层类型、头长、声明总长和全部块完整消费,读取唯一根节点的无命名空间包名、根节点的 Android 版本属性及直属 application 的 Android label。文本 Manifest 不作为可信身份来源,关闭该次分享;原有文本/二进制预检路径继续保留。原有最低 SDK/ABI 预检判定不能因分享解析失败而变化。

资源引用名称由独立 application_identity.rs 有界解析 resources.arsc:优先默认语言配置,其次简体中文、英语,仍无唯一可靠结果则为 null;最多追踪 8 层引用并检测循环。分享路径的 Manifest 解压读取上限 8 MiB、资源表上限 32 MiB,块偏移、长度和整数运算均检查边界;解码后的字符串总量和对象数量另设预算,不能通过重复偏移放大内存。异常只关闭该次分享。不得为分享重新执行一次 apktool 解包,也不引入新外部工具或网络查应用名称。首期只支持常规字符串资源;稀疏与 16 位偏移等未支持编码明确放弃名称解析,不按普通偏移数组误读,不承诺所有资源配置都能还原。

前端只传后端产生的检查引用与布尔选择,不传可信包名、名称或网络正文。后端在开始任务时校验检查引用与当前输入匹配,读取最新偏好并冻结版本与选择。解析期间输入被替换、重新校验身份不一致或引用过期时,跳过分享;不能把 A 应用的授权套到 B。

“加固成功”以现有核心成功返回及 protect_succeeded 标记为准,不靠进度文本猜测。独立签名以签名执行成功且任务成功终态为准,不因读取证书成功、对齐完成或进度达到 100% 就发送。签名输入只做共享的只读身份解析,不要求其满足加固预检资格,不额外解包 APK。

检查引用因过期清理或容量淘汰而删除前,先按后端可信包名撤销旧任务分享、清除待发送记录并关闭本会话分享,避免稍后取消因引用不存在而失去约束。此保守处理只减少分享,不影响任务,也不自动写入永久退出偏好;重新检查仍显示关闭,显式重新开启不恢复旧任务或旧重试。

任务结果 分享记录
仅加固成功 一条 operation=protect, flow=protect
加固并自动签名全部成功 一条 operation=protect, flow=protect_with_sign,不另发送独立签名记录
加固成功、后续自动签名失败 仍可发送一条 protect/protect_with_sign,只证明加固成功,不表明签名成功
独立签名成功 一条 operation=sign, flow=sign
核心加固失败、独立签名失败、终态取消 不发送

一次任务仅提交一次,不因页面重挂载或终态重复事件重复提交。分享通道不统计自动签名成功率,该指标仍由既有匿名功能统计承担;维护查询不得仅凭 flow=protect_with_sign 推定签名完成。

本地偏好与发送

应用级偏好放 config.toml 新的独立 application_sharing 分区,preferences 为包名到布尔值的映射,缺失键代表新应用默认 true。旧配置可读取,不修改 telemetry.enabled 或 shield.db 证书结构。

偏好保存失败必须让用户知道,并禁止该应用本次发送;当前会话仍保留取消状态,不能因保存失败恢复选中。无法读取、校验配置时失败关闭,不把损坏配置当成全部新应用。更新设置的全量保存不能覆盖该映射。

首期仅本进程内最多 32 条待发送记录,TTL 5 分钟,每份不超过 8 KiB;不在磁盘持久化包名上报队列,不在下次启动补传,不补发授权前的成功记录。关闭应用则放弃未发送记录,这是降低复杂度和敏感数据落盘的明确取舍。

非阻塞发送,10 秒超时,禁止重定向;网络故障或 5xx 最多在 30 秒后重试一次,429 和其他 4xx 不自动重试。发送前再次确认偏好,取消时清除该包名未发送记录;已发出的网络请求可能已被服务端接收,不能承诺撤回。发送状态不影响加固结果,不自动弹错误报告或递归计入加固失败。

服务端与维护查询

沿用现有 Worker/D1,独立 application-usage.js 及增量迁移。APPLICATION_SHARING_ENABLED 默认关闭,未配置 APPLICATION_SHARE_RATE_SECRET 时拒绝接收,不复用客户端静态密钥。来源按服务端收到的 IP 做带日期和通道前缀的 HMAC 限流,不存原始 IP、不与其他通道关联。

application_usage_submissions 保存上述字段、服务端 received_at 和规范载荷摘要。UUID 为主键:首次 201、相同 UUID 与载荷 200、冲突 409;校验失败 400、超大 413、达限 429、关闭或存储不可用 503。限流桶与插入在 D1 batch 中原子完成;来源每分钟最多 20 份、全局每天最多 2,000 份,分别有数据库约束,不能只在应用层先读后写。

同包名、应用版本、工具版本、操作类型、流程、成功日期的多次提交在维护查询中算同一条应用使用记录。网络重试由 UUID 去重;不同安装实例的相同包名也合并,故不可按记录数反推使用人数。重复操作次数不作为本通道指标,名称变更不制造新应用。

维护查询分别提供加固应用数、独立签名应用数、两者交集和包名并集;跨版本/跨月复用也按 operation 分开。只签名的应用不能计入加固复用;先加固后在签名页签名可有两种操作记录,但整体只算一个应用。

明细按服务端接收时间保留 180 天,限流桶 24 小时,下一次每日清理删除过期项;不声称精确到秒删除,也不把主库删除当作备份立即消失。不永久保存带包名的汇总。初期通过维护者授权 D1 查询,不建设管理站或公开读取接口,不输出到 stats 分支、发布资产或请求日志。

删除已提交记录与停止分享分开:首期由用户通过私下联系维护者提出删除请求,维护者核实对应范围后处理;不得凭一个公开包名开放匿名删除接口。公开展示应用名称或案例需要另外授权。

架构判断与方案取舍

新增私有应用信息通道属于跨端协议与数据模型变更,按 L3 评估。已经确认的产品取舍:不采用每次弹窗确认;不采用每次加固重置同包名取消偏好;采用新应用默认参与、单应用持久退出。完整隐私说明在设置页,不能因此省略说明本身。

保留边界:Manifest/资源解析只负责本地身份读取;GUI 分享模块负责偏好、任务快照和发送;服务端负责验证、存储与维护查询。main.rs 仅注册命令/状态;不把身份采集塞进通用错误报告或匿名统计模块,不给 shield-core 引入网络依赖。首期不重构整个 Manifest 子系统,不新增账号、设备识别、公开案例库、CLI 上报或 APK 运行时上报。

验收与版本安排

重点验证同包名取消跨重启和跨页保持、新包名仍默认选中、快速切包无串用、配置损坏失败关闭、任务选择冻结、加固/独立签名/自动签名的成功和失败口径、终态取消、未知名称留空、任意前端字段不能绕过后端生成、网络重试去重和跨页退出清除待发送。包含资源引用/多语言/循环/越界/超大 ZIP 样本、超大版本码、非法操作组合、应用并集去重、私有数据禁止字段、服务端原子限额/过期清理及旧客户端兼容。

目标版本已确认为 1.4.0-beta.6,不因为这一项升级次版本,不移动已发布标签。线上观察不是设计或开发前置条件。整个阶段完成本地测试、完整 macOS .app 与代码审查后统一提交 PR;按已授权发布任务完成远端迁移、启用和三平台发布。桌面人工交互与跨平台原生运行的未验项必须如实保留,不以构建通过替代。

实施任务见应用分享实施计划。

上线顺序、查询口径与删除边界见应用分享运维,开发测试不代替远端部署验收。