本页概述了各种方法,以确保安装在 Android 设备上的 APK 与原告模型中提出的声明相符。这包括从设备中提取相关 APK、检查其代码完整性,以及对提取的制品执行日志包含证明。
验证流程
透明度日志通过包含哈希值的 Merkle 树实现。 叶节点包含数据,而父节点包含其子节点的哈希值。
基本上,系统会对 Merkle 树执行两项计算,以验证透明度日志的防篡改属性:纳入证明和一致性证明。前者证明日志包含与特定 APK 版本对应的条目。日志条目包含一个哈希值,该哈希值是代码签名令牌(以 JSON Web 令牌 [JWT] 的形式)的 SHA256 摘要,可从相应的 APK 中获取。后者证明,当向树中添加新条目时,新检查点在加密方面与树的先前版本保持一致。
如需验证涵盖的 APK,请根据见证的检查点执行包含证明测试。请注意,我们计划使用标准化的见证协议将此日志与公共见证网络集成。这将提供经过见证的检查点,从而保证日志的一致性。
如果您想自行验证设备上的 APK 是否符合原告模型中的声明,请参阅下文。
纳入证明
Android 用户可以先提取 APK 及其相关元数据,然后将其重新计算的根哈希值与已发布的检查点中包含的根哈希值进行比较,从而检查设备上受覆盖的 APK 是否在日志中。如果匹配,则 Android 用户可以放心地享受威胁模型中所述的某些保护措施。
如何验证日志中是否包含 APK
如前所述,您可以在概览页面中找到当前涵盖的 APK 列表。
验证的前提条件
在继续操作以验证您刚刚从设备中提取的 APK 是否符合我们的声明之前,您需要通过从联网的计算机安装以下工具来获取这些工具。
Android 调试桥 (ADB)
ADB 是一种与 Android 设备通信的工具,可在 Android SDK Platform Tools 网站上获取。
AAPT2
AAPT2(Android 资源打包工具)是一种构建工具,用于编译和打包 Android 应用的资源。您可以在 Android SDK Build Tools 26.0.2 及更高版本中找到作为独立工具提供的 AAPT2。
bundletool
bundletool 是一种用于构建 Android App Bundle (AAB) 的工具。它还可用于将 AAB 转换为可在设备上安装的 APK。
您可以从 GitHub 下载该文件。
纳入证明验证器
这是一个 Go 模块,我们已将其发布到 Android 开源项目 (AOSP) 中名为 avb 的 Git 代码库中。该工具能够查询 Google 系统服务 APK 透明度日志,并输出软件包是否包含在日志中。有关此方法的用法示例,请参阅后面的部分。
如需下载此工具,您必须先克隆 avb 代码库。
computer:~$ git clone https://android.googlesource.com/platform/external/avb
验证器的源代码位于 avb 代码库中的 tools/transparency/verify 内。
构建用于验证的载荷
如需验证您根据我们的声明从设备中提取的 APK,您必须根据从 APK 派生的信息构建日志载荷。
在开始之前,请确保通过在设备上启用 adb 调试,可以在设备上使用 adb。
然后,找到 APK 在设备上的安装位置。在本指南中,我们将使用 Android System Key Verifier APK (com.google.android.contactkeys) 作为工作示例。
computer:~$ adb shell pm list packages -f | grep contactkeys
package:/data/app/~~i5WYSO4PuAAv798-eHdM7A==/com.google.android.contactkeys-PQCKjnn7xDqjeVhcUDibBA==/base.apk=com.google.android.contactkeys
如果 Android System Key Verifier APK 已安装在您的设备上,上述命令将返回一个路径,指明该 APK 在设备上的安装位置。 否则,您将不会看到任何输出。
然后,使用以下命令将 APK 从 Android 设备下载到您正在使用的计算机上(请注意,设备上的实际位置和 APK 文件名可能会有所不同):
computer:~$ mkdir -p /tmp/testdir && cd /tmp/testdir
computer:/tmp/testdir$ adb pull /data/app/~~i5WYSO4PuAAv798-eHdM7A==/com.google.android.contactkeys-PQCKjnn7xDqjeVhcUDibBA==/base.apk ./contactkeys_candidate.apk
如需获取并验证您刚刚下载的 APK 的软件包名称,您需要先解压缩该 APK,因为 APK 最终是一种特殊的 ZIP 文件。
computer:/tmp/testdir$ mkdir extracted && unzip contactkeys_candidate.apk -d extracted/
此步骤会解压缩构成 APK 的所有文件。您可以在 APK 的清单中找到软件包名称和版本,清单通常位于名为 AndroidManifest.xml 的文件中。
不过,获取的清单文件是二进制形式,无法直观易懂地读取。
为了将 XML 二进制文件转换为人类可读的形式,我们使用之前安装的 aapt2 工具(如前提条件部分中所述,该工具必须安装)。
computer:/tmp/testdir$ aapt2 dump badging ./contactkeys_candidate.apk
package: name='com.google.android.contactkeys' versionCode='7805' versionName='1.219.791156583' platformBuildVersionName='Baklava' platformBuildVersionCode='36' compileSdkVersion='36' compileSdkVersionCodename='Baklava'
从上面的输出中,我们可以确定此 APK 的软件包名称为 com.google.android.contactkeys,版本号 (versionCode) 为 1413。
现在,我们将搜索 APK 中的代码公开透明签名。它应该是 META-INF 文件夹中名为 code_transparency_signed.jwt 的文件,该文件夹包含从 APK 中提取的其他文件。
computer:/tmp/testdir$ sha256sum extracted/META-INF/code_transparency_signed.jwt
1779a2aee029112c2c9bfc9390b9678f3e5f4595b39705e8528dd522e8042f11 code_transparency_signed.jwt
有了此哈希字符串,我们现在就拥有了根据日志内容部分中所述格式拼凑日志载荷所需的所有信息。在此示例中,相应的日志载荷应如下所示:
1779a2aee029112c2c9bfc9390b9678f3e5f4595b39705e8528dd522e8042f11
SHA256(Signed Code Transparency JWT)
com.google.android.contactkeys
1143
另请注意软件包版本后面的换行符。
您可以将内容保存到文件中,例如 payload.txt。这在稍后进行包含证明测试时会派上用场。
验证 APK 代码签名的真实性
现在,我们应验证 APK 中嵌入的代码签名令牌的真实性。为此,我们使用 bundletool 和最初用于为其签名的密钥对的公钥。它们会发布到相应 APK 的每个部分中。假设您已将公钥证书(例如 Android 系统密钥验证器的公钥证书)保存到名为 signing_cert_pubkey.pem 的文件中,请按照以下指南执行代码签名验证。
首先,您应创建一个 ZIP 归档文件,并将候选 APK 添加到该 ZIP 归档文件中。
computer:/tmp/testdir$ zip -u test.zip contactkeys_candidate.apk
zip warning: test.zip not found or empty
adding: contactkeys_candidate.apk (deflated 58%)
computer:/tmp/testdir$ file test.zip
test.zip: Zip archive data, at least v2.0 to extract, compression method=deflate
现在,我们可以使用 bundletool 的 check-transparency 命令来验证候选 APK 中嵌入的代码签名是否与已发布的代码签名一致。
computer:/tmp/testdir$ java -jar BUNDLETOOL_INSTALL_PATH/bundletool-all-version.jar check-transparency \
--mode=apk \
--apk-zip=test.zip \
--transparency-key-certificate=signing_cert_pubkey.pem
APK signature is valid. SHA-256 fingerprint of the apk signing key certificate (must be compared with the developer's public key manually): D9 E1 73 5B 2A 39 51 27 3A 87 35 B7 66 9E F1 9E F5 3A F1 C1 27 5C BA 31 39 3C 18 40 8B 03 79 D0
Code transparency signature verified for the provided code transparency key certificate.
Code transparency verified: code related file contents match the code transparency file.
您应确保上述命令的输出表明代码公开透明签名和代码公开透明均已验证。
如果不是,例如,如果您看到类似 Code transparency verification failed because the provided public key
certificate does not match the transparency file 的输出,则表示相关 APK 的代码完整性可能已受到损害,您应该不信任该 APK。
请务必仔细检查,确保您是根据正确的公钥证书来验证这些签名。
否则,如果其他一切都正常,则表示您正在验证的 APK 的代码签名的真实性已通过验证。
验证软件包包含情况(包含证明)
使用您之前构建的载荷,您现在可以测试相关软件包是否已包含在透明度日志中。
Android 开源项目中的 avb 代码库中已发布纳入证明工具。如需运行该脚本,请执行以下操作:
computer:external/avb/tools/transparency/verify$ PAYLOAD_PATH=PATH_TO_PAYLOAD_DIR/payload.txt
computer:external/avb/tools/transparency/verify$ go build cmd/verifier/verifier.go
computer:external/avb/tools/transparency/verify$ ./verifier --payload_path=${PAYLOAD_PATH} --log_type=google_system_apk
验证者使用相应的检查点和日志内容(位于图块目录中)来检查您的 APK 载荷是否位于透明度日志中,从而验证它是否确实由 Google 发布。
命令的输出会写入 stdout:
OK. inclusion check success!如果软件包的代码包含在日志中,- 如果不是,则为
FAILURE。