先看结论与判断条件

  • 验收对象是当前发布候选实际解析并打包的依赖集合,不是采购合同、README 或 Gradle 声明中的理想集合。
  • 直接依赖与传递依赖必须共同锁定版本和来源仓库,否则同一份构建脚本可能在不同时间得到不同的 Native 载荷。
  • APK 内每个 lib/ABI 目录都要建立 SO 摘要、归属组件、引入路径和处置责任,缺少归属的二进制不能静默放行。
  • ABI 声明、构建产出、最终打包与设备运行是四类证据,任何一类都不能替代其余三类。
  • SLSA provenance 与 in-toto statement 适合绑定产物摘要和构建声明,但格式正确不等于声明真实,也不证明运行时安全。
  • 放行门禁应对新增、移除、版本漂移、摘要变化、未知 SO 和证明缺失分别给出责任人、处置时限与可审计结论。

先把验收对象从 SDK 名称改成候选包事实

AI SDK 往往不只是一项 Java 或 Kotlin 依赖。语音、视觉、推理和向量计算组件可能携带预编译本地库,也可能通过传递依赖继续引入运行时、图像编解码、网络或硬件适配库。采购单上写着一个 SDK 名称,最终 APK 中却可能出现多个组织、多个版本和多个 ABI 的二进制。供应链验收若只核对顶层坐标,会把真正进入进程的代码留在审计范围之外。

正确的验收对象应绑定一个不可混淆的发布候选,包括应用版本、构建编号、APK 或 AAB 摘要、签名身份、依赖解析结果和 APK 内文件摘要。团队随后才能回答三个基本问题:哪个组件把某个 SO 带进来,构建时拿到的是哪一份字节,出现安全通告或兼容故障时由谁负责处置。缺少候选摘要的清单只能作为计划,不能作为已验收记录。

这里还要区分声明、解析、打包和运行。Gradle 文件声明的是依赖意图,解析报告展示构建工具选中的版本,APK 清单展示交付文件,设备测试才说明特定环境是否成功加载。四者之间可能因版本冲突、排除规则、变体、拆包、压缩和厂商插件出现差异。工程判断是把四层证据分栏保存,而不是用一句“SDK 已接入”合并全部结论。

AI SDK Native 依赖验收的四层对象
证据层回答的问题最低记录不能替代的证据
依赖声明项目希望引入什么坐标、版本约束、仓库、变体解析后的真实版本
解析结果构建工具最终选择什么直接与传递依赖图、冲突原因APK 中真实文件
交付产物用户设备将收到什么候选摘要、SO 路径、文件摘要设备装载与业务结果
运行验证目标环境是否按预期执行设备、ABI、系统、日志、结果来源与构建证明
责任记录发生变更或漏洞由谁处理组件归属、联系人、处置状态任何技术层的原始证据

锁住解析图,才能解释直接依赖与传递依赖

Android Gradle dependency resolution 说明直接依赖与传递依赖会共同形成解析图,版本冲突、约束和选择规则会决定最终结果。对 AI SDK 来说,这意味着顶层版本没有变化时,传递组件仍可能因动态版本、仓库元数据、约束调整或其他库的升级而改变。验收应保存可重复生成的解析报告,并把每个节点的选择原因、被替代版本和引入路径作为清单字段。

版本锁定不能只记录 group、name、version。还需要记录下载仓库、制品类型、变体属性、校验摘要和依赖锁文件的来源提交。企业内部镜像可能缓存或重新托管同名制品,公共仓库也可能存在多个坐标指向相似组件。工程判断是把“坐标相同但字节不同”视为独立变更,门禁比较文件摘要,而不是看到版本字符串未变就自动沿用旧结论。

解析差异必须有可解释的基线。新增节点要说明业务需求和引入方,移除节点要确认功能是否迁移或被打包进其他制品,版本变化要关联变更说明与安全处置,来源仓库变化要重新确认信任边界。依赖树可以缩小调查范围,但不能单独证明某个 SDK 是故障或风险的唯一根因,因此结论应写成“发现变化并等待归属确认”,而不是直接给厂商定责。

依赖解析差异的处置规则
差异需要追问应保存的证据放行条件
新增依赖由谁引入,承担什么功能解析路径、制品摘要、评审记录归属和风险边界明确
版本变化兼容性与安全修复是什么旧新摘要、变更说明、回归结果变更理由与测试相互对应
来源变化仓库或镜像为何改变仓库标识、下载记录、校验摘要来源策略允许且摘要受控
依赖移除功能删除还是被合并解析差异、APK 文件差异没有残留未知载荷
冲突改选哪条规则覆盖了声明版本selection reason 与约束链负责人接受实际解析结果

从 APK 反查每个 SO 的 ABI、摘要与归属

Native 清单应从候选 APK 的 ZIP 条目开始,而不是从源码仓库猜测。常见本地库位于 lib/ABI/name.so,验收程序可以只读列举路径、未压缩大小和 SHA-256,再与依赖解析节点建立归属关系。若同名 SO 在多个 ABI 下出现,应分别计算摘要,因为不同架构的机器码本来就不同。若路径不符合约定或库名无法归属,门禁应产生待确认项。

Android ABIs 强调每个 ABI 有独立的调用约定、寄存器使用、数据对齐和设备支持范围。清单因此不能只写一个“支持 arm64”的布尔值,而应按 ABI 记录构建输入、SO 文件、依赖关系和设备验证。声明支持某个 ABI 不代表对应文件已经被构建和打包,也不代表它在真实设备上成功装载。静态清单能证明文件存在,运行结论仍要由目标设备证据承担。

归属映射通常无法只靠文件名完成。一个 SDK 可能重命名第三方库,也可能把多个开源组件静态链接到单个 SO;反过来,同一个基础库可能被多个 SDK 共同引用。可执行的做法是要求供应方给出组件清单和构建说明,再用 Gradle 解析图、AAR 内容、APK 路径与摘要交叉核对。无法拆分的静态组合应登记为组合件,并把漏洞处置责任明确到交付该组合件的一方。

APK 内 SO 清单的关键字段
字段用途异常信号处置动作
APK 路径定位 ABI 与文件名目录或命名不符合预期确认打包插件与交付方式
文件摘要绑定实际字节版本不变但摘要变化重新核对来源与构建
归属组件连接 SDK 与二进制未知或多个责任方补供应方说明和内部负责人
支持 ABI定义设备覆盖声明与文件集合不一致阻止扩大兼容结论
处置责任承接漏洞与升级只有采购方没有技术联系人补齐升级、回滚和通知路径

把 SDK Index 当作评审信号,不当作完整物料清单

Google Play SDK Index 可为部分商业 SDK 提供版本采用、权限、可靠性、安全和数据处理等评审线索。它适合在引入前帮助团队发现需要追问的问题,也适合在版本选择时补充外部视角。不过它不覆盖所有私有 SDK、开源库和企业内部构建物,更不会替项目列出 APK 中真实存在的每一个 SO。

使用 SDK Index 时,评审记录应保留查询对象、查询日期、对应版本和被采纳的具体建议。若 SDK 没有收录,结论只能是“该数据源没有覆盖”,不能推导为安全或不安全。若页面对权限、数据处理或版本状态给出提示,团队还要回到应用清单、运行配置和实际候选包核对,因为相同 SDK 在不同接入方式下可能暴露不同能力。

商业验收更关心问题能否闭环。采购合同应明确版本通知、Native 组件清单、漏洞通知、修复版本、停服或回滚方案和支持期限;技术清单负责证明当前候选包装了什么。两者连接后,外部评审信号才会变成可执行动作。只有风险标签而没有责任人和升级路径,通常会在真正出现通告时重新陷入临时追查。

  • 记录 SDK Index 查询日期与对应 SDK 版本
  • 未收录只标记数据源未覆盖,不作安全推断
  • 权限与数据处理提示回到真实清单和配置核对
  • 供应方交付 Native 组件和第三方许可证清单
  • 合同明确漏洞通知、修复版本与回滚联系人
  • 外部信号不能覆盖 APK 二进制清单

用 provenance 和 attestation 绑定构建声明与产物摘要

SLSA Provenance v1.1 把 provenance 组织为与产物主体、构建者、构建类型、外部参数和依赖材料有关的声明。对 AI SDK 验收而言,最有价值的不是获得一个文件名漂亮的证明,而是确认 subject 摘要与当前下载制品或最终候选中的对象能否对应,builder 身份是否属于认可边界,参数与材料是否足以解释这次构建。

in-toto Attestation Statement v1 提供将 artifact digest 与有类型声明负载绑定的通用结构。该结构能减少报告与候选包错配,但不会自动让声明内容变真。验收还需验证签名者、签名策略、声明类型和摘要算法,并确认门禁读取的是当前候选对应的声明。把未签名 JSON 附在交付目录里,只能算供应方说明,不能自动升级为可信构建证据。

证明链应允许出现不同证据等级。供应方能给出可验证 attestation 时,记录签名者、策略和摘要匹配结果;只能提供组件清单时,记录文件来源与人工复核;完全没有构建信息时,明确标成证明缺失,并由风险所有者决定是否接受。工程判断是拒绝用“有证明”这一布尔字段掩盖验证细节,门禁至少输出匹配、失配、无法验证三种状态。

构建证明的验证分层
检查项可核查事实常见误区门禁输出
subject 摘要是否匹配目标制品只比文件名或版本匹配、失配或缺失
builder 身份声明由谁产生任意签名都视为可信策略允许或待确认
buildType 与参数如何触发和配置构建参数存在就等于可重复信息充分或不足
依赖材料构建引用哪些输入材料清单替代最终包扫描可关联或不可关联
声明签名载荷是否保持完整格式正确就接受内容验证通过、失败或未验证

按 SSDF 明确供应方、研发、安全与发布责任

NIST SP 800-218 SSDF 把来源、构建、验证、变更和供应链风险放进安全开发流程。它是组织级实践框架,不会替项目决定某个 AI SDK 应否上线。团队可以借它拆清职责:供应方解释组件与构建来源,研发维护解析和集成,安全团队核对证明与风险,发布负责人把门禁结果绑定到候选身份,业务风险所有者处理仍未关闭的例外。

责任清单必须覆盖正常升级和紧急处置。正常升级要知道谁评审变更、谁维护回归样例、谁更新基线;安全通告到来时要能根据组件名、版本、SO 摘要和静态组合关系定位受影响候选;无法立即升级时要有禁用、回滚或风险接受路径。这里的关键不是承诺统一修复时长,而是确保每一类状态都有明确决策人和留痕方式。

例外也需要到期条件。某个私有 SDK 暂时没有 provenance,不应在表格里永久写“供应商原因”;应记录缺失内容、接受理由、适用候选、批准人、复核触发条件和替代证据。候选摘要变化、SDK 版本变化、未知 SO 出现或安全通告发布,都可以触发重新评审。没有触发器的例外会在后续版本中被无意识继承。

Native 供应链验收责任矩阵
角色输入责任判断责任必须留下的记录
SDK 供应方组件、版本、构建与许可证信息解释交付内容和修复路径清单、证明、通知联系人
应用研发解析图、集成配置、候选产物确认引入路径和业务影响锁文件、差异、回归结果
安全评审来源、摘要、通告与边界判定证据是否满足策略核验结果与未决项
发布负责人签名候选与门禁回执确认结果绑定正确候选摘要、签名身份、发布决定
风险所有者未关闭例外与业务影响接受、延期或拒绝理由、范围和复核触发器

用只读脚本生成可复核的 Native 供应链清单

自动化的第一步应保持只读和可重复。输入可以是一份由构建流程导出的依赖 JSON 与待验收 APK,输出每个依赖节点、每个 SO 的 ABI、路径、大小和摘要。脚本不需要修改 APK,也不应猜测未知二进制的厂商归属。它的职责是把事实稳定地摆到审阅者面前,并在依赖列表为空、APK 无效或没有 Native 文件时返回非零状态。

下面的 Python 示例读取命令行指定的依赖文件和 APK。依赖文件要求包含 dependencies 数组,每项提供 coordinate、source 和 sha256;脚本随后扫描 lib 目录,把 SO 按 ABI 汇总并计算摘要。输出中的 owner 保持 unresolved,直到团队用 AAR、供应方清单和解析路径补齐。这样的默认值比根据文件名自动归因更可靠,因为错归属会把后续漏洞通知交给错误责任方。

这段代码只能生成静态事实清单,不能证明库在设备上成功加载,也不能判断摘要对应的代码是否安全。生产流程还应保存脚本版本、输入文件摘要和执行日志,并把输出与基线比较。若发现新增 SO、摘要变化、未知来源或 ABI 集合改变,应由独立策略决定阻断还是进入例外审批,不能让清单生成器自行作商业风险结论。

  • 依赖输入来自同一候选的实际解析结果
  • APK 摘要和签名身份另行固定
  • 每个 SO 都按 ABI 保存路径与摘要
  • 未知 owner 必须进入人工归属队列
  • 脚本异常和空结果返回非零状态
  • 输出不代替设备运行与构建证明
读取依赖锁与 APK 中 SO 的只读清单生成器
from pathlib import Path
import hashlib
import json
import sys
import zipfile

if len(sys.argv) != 3:
    raise SystemExit(2)
lock_path = Path(sys.argv[1])
apk_path = Path(sys.argv[2])
if not lock_path.is_file() or not apk_path.is_file():
    raise SystemExit(2)
lock_data = json.loads(lock_path.read_text(encoding="utf-8"))
dependencies = lock_data.get("dependencies", [])
if not isinstance(dependencies, list) or not dependencies:
    raise SystemExit(2)
normalized_dependencies = []
for item in dependencies:
    coordinate = str(item.get("coordinate", "")).strip()
    source = str(item.get("source", "")).strip()
    digest = str(item.get("sha256", "")).lower().strip()
    if not coordinate or not source or len(digest) != 64:
        raise SystemExit(2)
    normalized_dependencies.append({"coordinate": coordinate, "source": source, "sha256": digest})
so_files = []
with zipfile.ZipFile(apk_path) as archive:
    for entry in archive.infolist():
        parts = entry.filename.split("/")
        if len(parts) == 3 and parts[0] == "lib" and entry.filename.endswith(".so"):
            payload = archive.read(entry)
            so_files.append({"abi": parts[1], "path": entry.filename, "size": entry.file_size, "sha256": hashlib.sha256(payload).hexdigest(), "owner": "unresolved"})
if not so_files:
    raise SystemExit(2)
result = {"apk": apk_path.name, "dependencies": normalized_dependencies, "nativeLibraries": sorted(so_files, key=lambda value: value["path"])}
print(json.dumps(result, ensure_ascii=False, indent=2))

把差异、限制和行动按钮写进最终放行记录

最终门禁不应只输出通过或失败。对每个候选,记录应列出依赖解析是否锁定、未知 SO 是否清零、ABI 声明与文件集合是否一致、制品摘要是否变化、provenance 或替代证据是否可核验、SDK Index 信号是否已处理、漏洞与升级责任是否明确。每项结论都要链接到原始证据,并保留检查时间和执行者。

放行条件需要与证据等级匹配。解析图和 APK 清单完整,可以证明当前候选包含什么;provenance 验证通过,可以证明某份声明与产物及构建身份的绑定;目标设备回归通过,才能对指定设备和场景记录运行结果。任何结论都应限定到对应候选、ABI 和设备范围。本文没有接入具体项目数据,因此不声称性能、兼容性、攻击阻断或客户结果。

准备引入或升级 AI SDK 时,可以先整理候选 APK、依赖锁文件、SDK 与 SO 对照表、支持 ABI、供应方证明、签名流程和设备矩阵,再通过御盾中央平台提交软件加固评估申请。评估入口的作用是承接真实材料与项目边界;在材料到位之前,供应链清单应保持待确认状态,不用营销承诺替代可复核证据。

  • 候选摘要、签名身份与清单一一绑定
  • 直接和传递依赖没有未解释漂移
  • 全部 SO 具备 ABI、摘要、来源与责任人
  • 证明状态区分匹配、失配与无法验证
  • 静态事实、工程判断和运行结果分栏记录
  • 例外包含批准人、适用范围与复核触发器
  • 申请评估时提交真实候选和验收边界

事实依据与适用边界

以下内容区分官方事实、本文工程判断和不能外推的范围,避免把设计建议写成未经验证的产品结论。

本文判断事实或工程依据适用限制
直接依赖和传递依赖共同决定构建最终解析到的组件版本。Android Gradle dependency resolution 描述依赖图、版本冲突、约束与选择规则。解析图只能解释构建选择,不能证明某个 SDK 是运行故障或安全问题的唯一根因。
SDK 评审可以参考版本采用、权限、可靠性、安全和数据处理等公开线索。Google Play SDK Index 提供部分商业 SDK 的评审信息与开发者指引。该索引不覆盖所有私有、开源或内部 SDK,也不替代候选 APK 的二进制清单。
不同 Android ABI 对调用约定、寄存器、对齐和设备覆盖有不同要求。Android ABIs 说明了 Android NDK 支持 ABI 的架构与约定差异。配置中声明 ABI 不证明对应 SO 已被构建、打包或在目标设备运行验证。
构建来源证明可以把产物主体与构建者、构建类型、外部参数和依赖材料关联。SLSA Provenance v1.1 定义 provenance 中 subject、builder、buildType、parameters 与 dependencies 等字段。provenance 记录构建声明,不单独证明产物没有漏洞或运行时行为安全。
供应链声明可以用产物摘要绑定有类型的证明负载。in-toto Attestation Statement v1 定义 subject 与 predicateType、predicate 的通用声明结构。声明格式正确不保证内容真实,仍需验证签名者、策略、摘要和当前候选的一致性。
安全开发流程应保留来源、构建、验证和变更证据,并管理供应链风险。NIST SP 800-218 SSDF 提供组织级安全软件开发实践与供应链风险框架。SSDF 不定义某个 App 加固产品的具体功能,也不替项目给出自动放行结论。
Native 依赖验收应同时绑定解析图、APK 内 SO、文件摘要、候选身份和责任记录。工程判断:这些字段把构建意图、交付字节和后续处置连接成可复核链路。清单完整只能证明记录闭合,实际安全性、兼容性和性能仍需项目证据验证。
未知 SO、来源变化、摘要漂移和证明缺失应分别进入显式门禁状态。工程判断:把不同缺口拆开,才能分配责任并避免用单一通过状态掩盖未决风险。是否阻断发布取决于项目风险策略,本文不提供通用阈值或具体项目放行结论。

工程常见问题

只锁定 AI SDK 的 Maven 版本,能否完成 Native 供应链验收?

不能。版本坐标只覆盖声明和部分解析信息,还要核对传递依赖、来源仓库、制品摘要、APK 内每个 ABI 的 SO、供应方证明、漏洞处置责任和当前候选身份。

为什么版本号没有变化,SO 摘要变化仍要重新评审?

因为同一坐标可能来自不同镜像或重新构建的制品,打包插件也可能改变最终载荷。摘要变化说明交付字节发生变化,应重新核对来源、构建说明和回归证据。

Google Play SDK Index 没有收录某个 SDK,是否意味着不能使用?

不能这样推断。未收录只表示该数据源没有覆盖。团队仍需通过供应方材料、依赖解析、APK 二进制清单、权限与数据配置、证明和设备测试完成自己的评审。

有 SLSA provenance 就能证明 AI SDK 安全吗?

不能。provenance 用来记录并绑定构建相关声明,还要验证签名者和产物摘要。它不会自动证明没有漏洞、没有恶意行为,也不替代运行时和业务回归。

静态链接进一个 SO 的多个组件怎样登记?

把该 SO 作为组合件登记,要求供应方给出内部组件和版本清单,并由交付组合件的一方承担漏洞通知与修复责任。无法拆分时要明确证据限制,不能按文件名猜测。

申请软件加固评估前需要准备哪些 Native 供应链材料?

准备真实候选 APK 或 AAB、文件摘要、签名流程说明、依赖锁与解析报告、SDK 和 SO 对照表、目标 ABI、供应方证明、例外清单及设备回归范围,再从御盾中央平台提交申请。

想用自己的 App 验证?

提交候选包、目标系统和关键业务路径,申请御盾 PoC 与兼容性评估。

继续阅读: 移动 AI 应用的运行时安全边界