אימות מלא של שקיפות בבקשות למוצרי Google

בדף הזה מוסבר איך לוודא שקובץ ה-APK או ה-APEX שהותקן במכשיר Android תואם לטענות שמופיעות במודל של בעל הזכויות. התהליך כולל שליפה של קובץ ה-APK מהמכשיר וביצוע הוכחה להכללת היומן בארטיפקט שחולץ.

תהליך האימות

יומן שקיפות מיושם באמצעות עץ מרקל שמורכב מגיבובים. צומת עלה מכיל נתונים, וצומת הורה מכיל את הגיבוב של הצמתים המשניים שלו.

שני חישובים בסיסיים מאמתים את המאפיין של יומני השקיפות שמעיד על שיבוש: הוכחת ההכללה והוכחת העקביות. הוכחת ההכללה מאשרת שהיומן כולל רשומה של גרסת APK ספציפית. רשומת היומן הזו מכילה גיבוב (hash), שהוא תקציר SHA256 של קובץ ה-APK שמותקן במכשיר. הוכחת העקביות מבטיחה שכאשר נוספות רשומות חדשות, נקודת הבדיקה החדשה נשארת עקבית מבחינה קריפטוגרפית עם גרסאות קודמות של העץ (או שלא בוצעו שינויים בעץ). במדריך הזה אנחנו מתמקדים בתהליך של חישוב הוכחת ההכללה, ומסתמכים על עדים כדי לבצע באופן רציף הוכחת עקביות מול נקודות הבדיקה האחרונות.

כדי לאמת קובץ APK מכוסה, צריך לבצע הוכחת הכללה מול נקודת ביקורת שנצפתה. שימו לב שאנחנו מתכננים לשלב את היומן הזה עם רשת עדים ציבורית באמצעות פרוטוקול עדים סטנדרטי. השילוב הזה יספק נקודות ביקורת מאומתות, ויבטיח את העקביות של היומן.

כדי לוודא שאפליקציות Google במכשיר תואמות לטענות שמופיעות במודל התובע, פועלים לפי השלבים הבאים.

הוכחת הכללה

כדי לוודא שקובץ APK שכלול בכיסוי במכשיר שלכם מופיע ביומן, אתם יכולים לחלץ את קובץ ה-APK, לחשב את הגיבוב שלו ולהשתמש בהוכחת הכללה כדי לבדוק אם הגיבוב הזה קיים בנקודת הבדיקה שפורסמה. הוכחת הכללה מוצלחת מספקת הגנה מפני הסיכונים שמתוארים במודל האיומים, ומאשרת שהאפליקציה היא אפליקציית Google לגיטימית.

איך מאמתים הכללה של קובץ APK ביומן

אפשר לאמת כל אפליקציית Google שטוענת שהיא אפליקציית צד ראשון באמצעות היומן הזה.

דרישות מוקדמות לאימות

לפני שממשיכים לאימות של הארטיפקט (קושחה או APK) בהתאם לטענה, צריך לוודא שהכלים הבאים זמינים במחשב שמחובר לרשת. בהתאם ליעד האימות, יכול להיות שלא תצטרכו את כולם.

Golang

כלי האימות כתוב ב-Go. כדי ליצור אותו, צריך להתקין את Go בגרסה 1.24 ואילך מאתר Go.

Android Debug Bridge‏ (ADB)

‫ADB הוא כלי שמתקשר עם מכשיר Android כדי לבדוק את התמונה או לחלץ קובצי APK. הכלי זמין באתר של Android SDK Platform Tools‏ .

כלי לאימות הוכחת הכללה

המאמת של הוכחת ההכללה הוא מודול Go שמבצע שאילתה ביומן השקיפות ומחזיר פלט שמציין אם ארטיפקט כלול ביומן. הוא מתפרסם במאגר של android-binary-transparency ב-GitHub בכתובת https://github.com/android/android-binary-transparency/tree/main

כדי לשכפל את מאגר AOSP avb:

computer:~$ git clone https://android.googlesource.com/platform/external/avb

כדי לשכפל את המאגר של android-binary-transparency ב-GitHub:

computer:~$ git clone https://github.com/android/android-binary-transparency

AAPT2

‫AAPT2 (Android Asset Packaging Tool) הוא כלי לבנייה שמשמש לקומפילציה ולאריזה של משאבים של אפליקציית Android. הוא זמין ככלי נפרד ב-Android SDK Build Tools מגרסה 26.0.2 ואילך.

bundletool

‫bundletool הוא כלי שמשמש ליצירת קובץ Android App Bundle ‏ (AAB). אפשר להשתמש בו גם כדי לאמת חתימות קוד של APK. אפשר להוריד אותו מ-GitHub.

wget או curl

‫wget ו-curl הם כלים שאפשר להשתמש בהם כדי לאחזר או להוריד קבצים מהאינטרנט. חשוב לוודא שאחד מהכלים האלה מותקן, כי יכול להיות שתסריטי האימות יסתמכו עליהם.

Avbtool

‫avbtool משמש לחישוב תקציר VBMeta של גיבויי קושחה ולאימות של קבצים בינאריים. אחרי שמשכפלים את המאגר של avb (כפי שמוצג בקטע "אימות הוכחת הכללה"), אפשר למצוא את avbtool.py בתוך הספרייה המשוכפלת של avb. צריך להוסיף את הספרייה הזו למשתנה הסביבה $PATH.

computer:~$ PATH=$PATH:DIRECTORY_CONTAINING_AVBTOOL

Fbpacktool

‫fbpacktool הוא סקריפט Python שמשמש לפריקת רכיבים נפרדים ב-bootloader.img של Pixel. אין צורך בכך אם מאמתים קובצי APK. הכלי הזה חשוב כי הוא מאפשר ל-avbtool.py לגלות את התמונות הנדרשות לאימות.

כדי להשתמש ב-fbpacktool צריך להתקין את Python בגרסה 3.6 ואילך ואת החבילה PyYAML (לדוגמה, python3 -m pip install pyyaml).

כדי להשתמש בכלי הזה, צריך להוריד את ששת הסקריפטים הבאים של Python לספרייה שבה נמצא avbtool.py, להפוך את fbpacktool.py לקובץ הפעלה וליצור קישור סימבולי בשם fbpacktool ל-fbpacktool.py לנוחות.

אם יש לכם wget:

computer:dir_to_avbtool$ wget https://developers.google.com/android/binary_transparency/tools/pixel/fbpacktool/fbpacktool.py \
https://developers.google.com/android/binary_transparency/tools/pixel/fbpacktool/fbpack.py \
https://developers.google.com/android/binary_transparency/tools/pixel/fbpacktool/packedstruct.py \
https://developers.google.com/android/binary_transparency/tools/pixel/fbpacktool/xmlparser.py \
https://developers.google.com/android/binary_transparency/tools/pixel/fbpacktool/xmlserializer.py \
https://developers.google.com/android/binary_transparency/tools/pixel/fbpacktool/yamlparser.py
computer:dir_to_avbtool$ chmod +x fbpacktool.py
computer:dir_to_avbtool$ ln -s fbpacktool.py fbpacktool

אם יש לכם curl:

computer:dir_to_avbtool$ curl -LO https://developers.google.com/android/binary_transparency/tools/pixel/fbpacktool/fbpacktool.py
computer:dir_to_avbtool$ curl -LO https://developers.google.com/android/binary_transparency/tools/pixel/fbpacktool/fbpack.py
computer:dir_to_avbtool$ curl -LO https://developers.google.com/android/binary_transparency/tools/pixel/fbpacktool/packedstruct.py
computer:dir_to_avbtool$ curl -LO https://developers.google.com/android/binary_transparency/tools/pixel/fbpacktool/xmlparser.py
computer:dir_to_avbtool$ curl -LO https://developers.google.com/android/binary_transparency/tools/pixel/fbpacktool/xmlserializer.py
computer:dir_to_avbtool$ curl -LO https://developers.google.com/android/binary_transparency/tools/pixel/fbpacktool/yamlparser.py
computer:dir_to_avbtool$ chmod +x fbpacktool.py
computer:dir_to_avbtool$ ln -s fbpacktool.py fbpacktool

OpenSSL

‫openssl עוזר לבצע פעולות קריפטוגרפיות שונות באמצעות הטרמינל בתהליך העבודה של האימות. מוודאים שהיא מותקנת במערכת. כדי לבדוק בטרמינל, מריצים את הפקודה הבאה ומוודאים שהתוצאה שמוחזרת לא ריקה:

computer:~$ which openssl
/usr/bin/openssl

יצירת מטען ייעודי (payload) לאימות

כדי לאמת את קובץ ה-APK שחולץ, צריך ליצור מטען ייעודי (payload) של יומן באמצעות מידע שנגזר מקובץ ה-APK עצמו.

לפני שמתחילים, מפעילים את ניפוי הבאגים ב-USB במכשיר כדי לאפשר חיבורים של adb.

לאחר מכן, מאתרים את קובץ ה-APK שהותקן במכשיר. במדריך הזה משתמשים ב-Google Play Services APK (com.google.android.gms) כדוגמה.

adb shell pm path com.google.android.gms

הפלט אמור להיראות כך:

computer:~$ adb shell pm path com.google.android.gms
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/base.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_CronetDynamite_installtime.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_DynamiteLoader_installtime.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_DynamiteModulesA_installtime.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_DynamiteModulesC_installtime.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_GoogleCertificates_installtime.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_MapsDynamite_installtime.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_MeasurementDynamite_installtime.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_config.en.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_config.xxhdpi.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_maps_core_dynamite_ondemand.apk

הפלט הזה מציין שקובץ APK בסיסי אחד וכמה קובצי APK מפוצלים מותקנים בשביל com.google.android.gms במכשיר. המספר המדויק של קובצי ה-APK המפוצלים משתנה בהתאם לתצורת המכשיר. לכל קובץ APK מפוצל יש את אותו שם חבילה וקוד גרסה כמו לקובץ ה-APK הבסיסי.

מורידים את קובצי ה-APK שברשימה ממכשיר ה-Android למחשב באמצעות הפקודה הבאה (שימו לב שנתיבי הקבצים בפועל עשויים להשתנות):

mkdir -p /tmp/testdir/gms && cd /tmp/testdir/gms && \
adb shell pm path com.google.android.gms | cut -d':' -f2 | tr -d '\r' | xargs -n1 adb pull

כדי לאמת את שם החבילה ואת הגרסה של קובצי ה-APK שהורדתם, צריך לבדוק את המניפסט שלהם (AndroidManifest.xml).

מכיוון שהמניפסט בתוך קובץ APK הוא בפורמט בינארי, צריך להשתמש בכלי aapt2 (שמותקן במהלך שלב הדרישות המוקדמות) כדי לחלץ את המידע ולקרוא אותו ישירות מקובץ ה-APK:

computer:/tmp/testdir/gms$ aapt2 dump badging ./base.apk
package: name='com.google.android.gms' versionCode='260834035' versionName='26.08.34 (260400-876566425)' platformBuildVersionName='Baklava' platformBuildVersionCode='36' compileSdkVersion='36' compileSdkVersionCodename='Baklava'
minSdkVersion:'35'
targetSdkVersion:'36'
...

כדי לקבל את המידע הרלוונטי, צריך לחזור על השלב הזה עד שמתקבלים נתונים לגבי כל קובצי ה-APK המפוצלים שמותקנים במכשיר.

הפלט מאשר ששם החבילה של ה-APK הוא com.google.android.gms ומספר הגרסה (versionCode) הוא 260834035.

בשלב הבא, מחשבים את הגיבוב הקריפטוגרפי של כל APK:

computer:/tmp/testdir/gms$ sha256sum *.apk
66aa2d7b9752cdd61065b55c8e16739d8367fa18a0f1c8c84122369f86958f1a  base.apk
c20754aee886cc55a9de91ee15c623c59d94ad22b7e435a1a48afc43cf1a106c  split_config.en.apk
68c09b63a1262e0d34020c139bc77deff3c32bd2b01177abac64790a62fb3be6  split_config.xxhdpi.apk
cd746820c27babd855fa5daea6fabcdf7b44abf3060bc547adc4219212410af0  split_CronetDynamite_installtime.apk
512ee48b60fdb0787a17f84a7dc448fdbf885b2b86a9cb50525d4c22d561b0f1  split_DynamiteLoader_installtime.apk
9e0c74bdc75c50c80d4e2e580a7eda6b8391423ab1161645f41ec6cadc07d678  split_DynamiteModulesA_installtime.apk
955780ac01f59b98bd9be12968f3824ad71b762620f7bf223c569c1a6ab7056c  split_DynamiteModulesC_installtime.apk
34c4a2e32d31554d55fc1519e2cfc3ed5027a090fb29b54cfc99f42d1da43bc5  split_GoogleCertificates_installtime.apk
475e18dde92472cde9d8300c082b6dc269613db03398bcd9d1987dff3e68f7b5  split_maps_core_dynamite_ondemand.apk
f83faf40f08bc13f4879302e01c08c863ca2304b4b4e7c9eaf8cd1e869bb6573  split_MapsDynamite_installtime.apk
ec6d854ddda6cd1ba2ba7af2d9fdf4f28c5c78be8713c64521c785429296738c  split_MeasurementDynamite_installtime.apk

עכשיו יש לכם את כל המידע שצריך כדי ליצור מטען ייעודי (payload) של יומן, בפורמט שמתואר בקטע "תוכן היומן". אם בוחרים ערך גיבוב אחד מהתוצאות כדוגמה (צריך לאמת את ערך הגיבוב של כל קובץ APK מפוצל), מטען הייעודי (payload) של היומן נראה כך:

66aa2d7b9752cdd61065b55c8e16739d8367fa18a0f1c8c84122369f86958f1a
SHA256(APK)
com.google.android.gms
260834035

חשוב לוודא שמוסיפים תו של שורה חדשה בסוף הקובץ. שומרים את התוכן הזה בקובץ, למשל payload.txt, כדי להשתמש בו עם הכלי verifier בהמשך.

אימות הכללת החבילה (הוכחת הכללה)

אחרי שיוצרים את המטען הייעודי (payload), אפשר לבדוק אם החבילה נכללת ביומן השקיפות. בונים את הכלי להוכחת הכללה ממאגר android-binary-transparency ששכפלתם קודם:

go build cmd/verifier/verifier.go

התוצאה אמורה להיות קובץ הפעלה בשם verifier בספרייה הזו. מריצים את כלי האימות, מספקים את הנתיב למטען הייעודי (payload) ומציינים את סוג היומן:

computer:android-binary-transparency$ PAYLOAD_PATH=PATH_TO_PAYLOAD_DIR/payload.txt
computer:android-binary-transparency$ ./verifier --payload_path=${PAYLOAD_PATH} --log_type=google_1p_apk

המאמת משתמש בנקודת הבדיקה ובתוכן היומן (מספריית המשבצות) כדי לבדוק אם המטען הייעודי (payload) של ה-APK נמצא ביומן השקיפות, וכך לאשר שהוא פורסם על ידי Google.

הפלט של הפקודה מועבר אל stderr:

  • ‫OK. inclusion check success! אם החבילה כלולה ביומן.
  • FAILURE אם הוא לא מותקן.

אימות אוטומטי של כל החבילות במכשיר

בגלל מספר האפליקציות של Google שעשויות להיות מותקנות מראש במכשיר, יכול להיות שיהיה מייגע למנות כל אפליקציה ולבצע הוכחות הכללה בנפרד.

אנחנו מספקים כלי אוטומטי נוסף שנקרא Uraniborg, שיכול לזהות ולמדוד את כל החבילות שמותקנות כרגע במכשיר. הפלט של הכלי הזה מוזן ישירות לכלי verifier, וכך אפשר לגלות ולאמת את השקיפות של כל האפליקציות במכשיר בשלב אחד.

כדי להשתמש בתהליך העבודה האוטומטי הזה, ודאו שמכשיר ה-Android מחובר למחשב באמצעות ADB. קוד המקור של Uraniborg כלול גם במאגר android-binary-transparency.

מריצים את הסקריפט automate_observation.py שנמצא בספרייה scripts/python:

python3 automate_observation.py --pull-all-apks --perform_inclusion_proof_check --verifier_path <path_to_verifier_executable>

בסיום הפעלת הסקריפט, הפלט אמור להיראות כך:

INFO:automate_observation.py:main(858): SUCCESS! Hubble was successfully deployed and executed on connected device ABCDEFGHN01234.
INFO:automate_observation.py:main(860): Hubble output files can be found at: /Users/user/home/src/android-binary-transparency/uraniborg/scripts/python/results/google/lynx/lynx:16/BP4A.260105.004.E1/14587043:user/release-keys/001

עוברים לספריית הפלט שמצוינת בסקריפט. בתוך התיקייה, מאתרים את הקובץ בשם packages_with_inclusion_proof_signal.txt. בקובץ הזה מפורטת כל חבילה שהותקנה, לצד שדה inclusion_proof_verified שמוגדר כ-true או כ-false. הערך true מציין שהחבילה אומתה באופן קריפטוגרפי מול יומן השקיפות, ושהיא עומדת בדרישות של היומן.