Google 系統服務 APK 資訊公開完整驗證

本頁概略說明各種方法,確保在 Android 裝置上安裝的 APK 與 Claimant Model 中的聲明相符。這包括從裝置中提取有疑慮的 APK、檢查其程式碼完整性,以及對擷取的構件執行記錄納入證明。

驗證程序

透明化記錄是使用由雜湊值組成的 Merkle 樹實作。葉節點包含資料,而父項節點則包含子項的雜湊值。

基本上,系統會在 Merkle 樹狀結構上執行兩項運算,驗證透明化記錄的防竄改屬性:包含證明和一致性證明。前者證明記錄包含與特定 APK 版本相對應的項目。記錄項目包含雜湊,這是程式碼簽章權杖的 SHA256 摘要,以 JSON Web Token (JWT) 的形式提供,可從對應的 APK 取得。後者證明在樹狀結構中新增項目時,新檢查點會與先前版本的樹狀結構 (加密) 一致。

如要驗證已涵蓋的 APK,請根據目睹的檢查點執行包含證明測試。請注意,我們預計使用標準化的見證協定,將這份記錄與公開見證網路整合。這會提供監控的檢查點,確保記錄的一致性。

如要確認裝置上的 APK 是否符合聲明方模型中所述的聲明,請參閱下文。

證明已納入

Android 使用者可以先擷取 APK 及其相關中繼資料,然後將重新計算的根雜湊與已發布檢查點所含的根雜湊進行比較,藉此檢查裝置上涵蓋的 APK 是否位於記錄中。如果兩者相符,Android 使用者就能放心,因為系統會提供威脅模型中所述的某些防護措施。

如何驗證記錄檔中是否包含 APK

如前文所述,您可以在總覽頁面中,查看目前涵蓋的 APK 清單。

驗證前必要條件

在繼續驗證剛從裝置中擷取的 APK 是否符合我們的聲明之前,您需要從已連上網路的電腦上安裝下列工具。

Android Debug Bridge (ADB)

ADB 是用於與 Android 裝置通訊的工具,可在 Android SDK 平台工具 網站上取得。

bundletool

bundletool 是用於建構 Android App Bundle (AAB) 的工具。也可以用來將 AAB 轉換成可在裝置上安裝的 APK。您可以從 GitHub 下載。

Androguard

Androguard 是一組用於分析 APK 的工具。您可以前往 Androguard 網站下載及安裝這項工具。

包容證明驗證器

這是我們在 Android 開放原始碼計畫 (AOSP) 中名為 avb 的 Git 存放區中發布的 Go 模組。它可以查詢 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 在裝置上的安裝位置。否則,您不會看到任何輸出內容。

接著,使用下列指令,從 Android 裝置將 APK 下載到您正在使用的電腦上 (請注意,裝置上的實際位置和 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 轉換為人類可讀的格式,我們會使用 androguard 套件的 axml 工具 (如需安裝,請參閱「必要條件」一節)。

computer:/tmp/testdir$ androguard axml extracted/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1413" android:versionName="1.48.688082145" android:compileSdkVersion="35" android:compileSdkVersionCodename="VanillaIceCream" android:requiredSplitTypes="" android:splitTypes="" package="com.google.android.contactkeys" platformBuildVersionCode="35" platformBuildVersionName="VanillaIceCream">

根據上述輸出內容,我們現在可以確定這個 APK 的套件名稱為 com.google.android.contactkeys,版本號碼 (versionCode) 則為 1413

接下來,我們會在 APK 中搜尋程式碼透明性簽名。這個檔案應為 code_transparency_signed.jwt 檔案,位於 APK 中其他已擷取檔案所在的 META-INF 資料夾中。

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 和金鑰組的公開金鑰,該金鑰組最初用於簽署 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

我們現在可以使用 bundletoolcheck-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