应用包的代码透明度

代码透明度是使用 Android 应用包发布的应用的一种可选代码签名和验证机制。它使用代码透明度签名密钥,该密钥仅由应用开发者持有。

代码透明度独立于用于应用包和 APK 的签名方案。代码透明度密钥与使用Play 应用签名时存储在 Google 安全基础架构上的应用签名密钥是独立且不同的。

代码透明度的工作原理

该过程通过在构建应用包后但在将其上传到 Play Console 进行分发之前,将代码透明度文件包含在应用包中来实现。

代码透明度文件是一个 JSON Web 令牌 (JWT),其中包含应用包中包含的 DEX 文件和原生库及其哈希值列表。然后使用仅由开发者持有的代码透明度密钥对其进行签名。

Code transparency diagram

此代码透明度文件会传播到从应用包构建的基本 APK(特别是基本模块的主拆分)。然后可以验证:

  • APK 中存在的所有 DEX 和原生代码文件在代码透明度文件中具有匹配的哈希值。
  • 应用中代码透明度签名密钥的公钥组件与开发者的公钥匹配(开发者必须通过单独的安全通道提供)。

这些信息共同验证 APK 中包含的代码与开发者最初的意图相符,并且未被修改。

代码透明度文件不验证资源、资产、Android 清单或任何其他非 DEX 文件或 lib/ 文件夹中包含的原生库。

代码透明度验证仅用于开发人员和最终用户检查的目的,他们希望确保他们正在运行的代码与应用开发者最初构建和签名的代码相符。

已知限制

在某些情况下,无法使用代码透明度

  • 在清单中指定sharedUserId属性的应用。此类应用可能与其它的应用共享其进程,这使得难以确保它们正在执行的代码。
  • 使用防篡改保护或在生成代码透明度文件后进行代码更改的任何其他服务的应用将导致代码透明度验证失败。
  • 在 API 级别低于 21(Android 5.0)的应用使用旧版 Multidex 并使用功能模块。当应用由 Google Play 安装在 Android 5.0+ 设备上时,代码透明度将继续工作。在较旧的操作系统版本上,代码透明度将被禁用。

如何添加代码透明度

在您可以向应用添加代码透明度之前,请确保您拥有可用于代码透明度签名的私钥和公钥对。这应该是一个与您用于 Play 应用签名的应用签名密钥不同的唯一密钥,并且必须安全保存,并且永远不要在您的组织外部共享。

如果您没有密钥,您可以按照签名您的应用指南中的说明在您的机器上生成一个密钥。代码透明度使用标准密钥库文件,因此即使该指南用于应用签名,密钥生成过程也是相同的。

使用 Android Gradle 插件

代码透明度支持需要 Android Gradle 插件版本 7.1.0-alpha03 或更高版本。要配置用于代码透明度签名的密钥,请在 bundle 块中添加以下内容。

Groovy

// In your app module's build.gradle file:
android {
    ...
    bundle {
        codeTransparency {
            signing {
                keyAlias = "ALIAS"
                keyPassword = "PASSWORD"
                storeFile = file("path/to/keystore")
                storePassword = "PASSWORD"
            }
        }
        ...
    }
}

Kotlin

// In your app module's build.gradle.kts file:
android {
    ...
    bundle {
        codeTransparency {
            signing {
                keyAlias = "ALIAS"
                keyPassword = "PASSWORD"
                storeFile = file("path/to/keystore")
                storePassword = "PASSWORD"
            }
        }
        ...
    }
}

使用的密钥必须是您仅用于代码透明度的密钥,而不是 Play 应用签名使用的应用签名密钥。

在命令行上使用 bundletool

代码透明度支持需要 bundletool 版本 1.7.0 或更高版本,您可以从 GitHub 下载

运行以下命令可将代码透明度添加到 Android 应用包。使用的密钥必须是您仅用于代码透明度的密钥,而不是 Play 应用签名使用的应用签名密钥。

bundletool add-transparency \
  --bundle=/MyApp/my_app.aab \
  --output=/MyApp/my_app_with_transparency.aab \
  --ks=/MyApp/keystore.jks \
  --ks-pass=file:/MyApp/keystore.pwd \
  --ks-key-alias=MyKeyAlias \
  --key-pass=file:/MyApp/key.pwd

或者,如果您想使用您自己的签名工具,您可以使用 bundletool 生成未签名的代码透明度文件,在单独的环境中对其进行签名,并将签名注入到应用包中。

# Generate code transparency file
bundletool add-transparency \
  --mode=generate_code_transparency_file \
  --bundle=/MyApp/my_app.aab \
  --output=/MyApp/code_transparency_file.jwt \
  --transparency-key-certificate=/MyApp/transparency.cert

# Add code transparency signature to the bundle
bundletool add-transparency \
  --mode=inject_signature \
  --bundle=/MyApp/my_app.aab \
  --output=/MyApp/my_app_with_transparency.aab \
  --transparency-key-certificate=/MyApp/transparency.cert \
  --transparency-signature=/MyApp/signature

验证应用的代码透明度

根据 APK 是否安装在 Android 设备上或已下载到您的电脑本地,验证代码与代码透明性文件的方法有所不同。

使用 Bundletool 检查应用包或 APK 集

您可以使用 bundletool 验证应用包或 APK 集中的代码透明性。使用 check-transparency 命令打印公钥指纹。

# For checking a bundle:
bundletool check-transparency \
  --mode=bundle \
  --bundle=/MyApp/my_app_with_transparency.aab

No APK present. APK signature was not checked.
Code transparency signature is valid. SHA-256 fingerprint of the code transparency key certificate (must be compared with the developer's public key manually): 01 23 45 67 89 AB CD EF ..
Code transparency verified: code related file contents match the code transparency file.


# For checking a ZIP containing app's APK splits:
bundletool check-transparency \
  --mode=apk \
  --apk-zip=/MyApp/my_app_with_transparency.zip

APK signature is valid. SHA-256 fingerprint of the apk signing key certificate (must be compared with the developer's public key manually): 02 34 E5 98 CD A7 B2 12 ..
Code transparency signature is valid. SHA-256 fingerprint of the code transparency key certificate (must be compared with the developer's public key manually): 01 23 45 67 89 AB CD EF ..
Code transparency verified: code related file contents match the code transparency file.

您可以选择性地指定要针对其验证应用包或 APK 集的公钥,这样您就不必手动比较哈希值。

bundletool check-transparency \
  --mode=bundle \
  --bundle=/MyApp/my_app_with_transparency.aab \
  --transparency-key-certificate=/MyApp/transparency.cert

No APK present. APK signature was not checked.
Code transparency signature verified for the provided code transparency key certificate.
Code transparency verified: code related file contents match the code transparency file.


bundletool check-transparency \
  --mode=apk \
  --apk-zip=/MyApp/my_app_with_transparency.zip \
  --apk-signing-key-certificate=/MyApp/apk.cert \
  --transparency-key-certificate=/MyApp/transparency.cert

APK signature verified for the provided apk signing key certificate.
Code transparency signature verified for the provided code transparency key certificate.
Code transparency verified: code related file contents match the code transparency file.

使用 Bundletool 检查安装在设备上的应用

要检查已安装在 Android 设备上的应用,请确保设备已通过 ADB 连接到您的电脑,并发出以下命令。

bundletool check-transparency \
  --mode=connected_device \
  --package-name="com.my.app"

APK signature is valid. SHA-256 fingerprint of the apk signing key certificate (must be compared with the developer's public key manually): 02 34 E5 98 CD A7 B2 12 ..
Code transparency signature is valid. SHA-256 fingerprint of the code transparency key certificate (must be compared with the developer's public key manually): 01 23 45 67 89 AB CD EF ..
Code transparency verified: code related file contents match the code transparency file.

已连接设备的透明性检查还可以选择性地根据您指定的公钥验证签名。

bundletool check-transparency \
  --mode=connected-device \
  --package-name="com.my.app" \
  --apk-signing-key-certificate=/MyApp/apk.cert \
  --transparency-key-certificate=/MyApp/transparency.cert

APK signature verified for the provided apk signing key certificate.
Code transparency signature verified for the provided code transparency key certificate.
Code transparency verified: code related file contents match the code transparency file.