应用包的代码透明度

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

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

代码透明度的运作方式

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

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

Code transparency diagram

此代码透明度文件被传播到从应用包构建的基本 APK(具体而言是基本模块的主拆分)。然后,可以验证以下内容:

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

这些信息共同验证了 APK 中包含的代码与开发者最初打算的代码一致,并且未被修改。

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

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

已知限制

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

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

如何添加代码透明度

在为应用添加代码透明度之前,请确保您拥有可用于代码透明度签名的私钥和公钥对。这应该是一个唯一的密钥,与您用于 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

验证应用的代码透明度

根据您是在 Android 设备上安装了 APK 还是本地下载到计算机上,有不同的方法可以验证代码与代码透明度文件是否一致。

使用 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.