Google 제품 애플리케이션 투명성 전체 인증

이 페이지에서는 Android 기기에 설치된 APK 또는 APEX가 신고자 모델에 명시된 주장과 일치하는지 확인하는 방법을 설명합니다. 이 프로세스에는 기기에서 APK를 가져오고 추출된 아티팩트에 로그 포함 증명을 실행하는 작업이 포함됩니다.

인증 프로세스

투명성 로그는 해시로 구성된 Merkle 트리로 구현됩니다. 리프 노드에는 데이터가 포함되고 상위 노드에는 하위 노드의 해시가 포함됩니다.

두 가지 기본 계산을 통해 투명성 로그의 변조 방지 속성을 인증합니다. 포함 증명과 일관성 증명입니다. 포함 증명은 로그에 특정 APK 버전의 항목이 포함되어 있는지 확인합니다. 이 로그 항목에는 기기에 설치된 APK 파일의 SHA256 다이제스트인 해시가 포함되어 있습니다. 일관성 증명은 새 항목이 추가될 때 새 체크포인트가 이전 버전의 트리와 암호화 방식으로 일관성을 유지하는지 (또는 트리가 변조되지 않았는지) 확인합니다. 이 가이드에서는 포함 증명 계산 프로세스에 중점을 두는 반면, 증인은 최신 체크포인트에 대해 일관성 증명을 지속적으로 실행합니다.

적용되는 APK를 인증하려면 증인이 확인한 체크포인트에 대해 포함 증명을 실행합니다. 표준화된 증인 프로토콜을 사용하여 이 로그를 공개 증인 네트워크와 통합할 계획입니다. 이 통합은 증인이 확인한 체크포인트를 제공하여 로그의 일관성을 보장합니다.

기기의 Google 앱이 신고자 모델에 명시된 주장과 일치하는지 확인하려면 다음 단계를 따르세요.

포함 증명

APK를 추출하고 해시를 계산한 후 포함 증명을 사용하여 게시된 체크포인트에 해당 해시가 있는지 확인하여 기기의 적용되는 APK가 로그에 있는지 확인할 수 있습니다. 포함 증명이 성공하면 위협 모델에 설명된 위험을 방지할 수 있으며 앱이 합법적인 Google 앱임을 확인할 수 있습니다.

로그에서 APK 포함을 확인하는 방법

Google의 1st party 앱이라고 주장하는 모든 앱은 이 로그에 대해 인증할 수 있습니다.

인증을 위한 기본 요건

추출된 APK를 인증하기 전에 컴퓨터에 다음 도구를 설치해야 합니다.

Android 디버그 브리지 (ADB)

ADB는 Android 기기와 통신하는 도구로, Android SDK 플랫폼 도구 웹사이트에서 사용할 수 있습니다.

AAPT2

AAPT2 (Android Asset Packaging Tool)는 Android 앱의 리소스를 컴파일하고 패키징하는 데 사용되는 빌드 도구입니다. Android SDK 빌드 도구 26.0.2 이상에서 독립형 도구로 사용할 수 있습니다.

Golang

인증 도구는 Go로 작성됩니다. 빌드하려면 Go 사이트에서 Go 1.17 이상을 설치하세요.

포함 증명 인증자

android-binary-transparency GitHub 저장소에 verifier라는 Go 모듈을 게시합니다. 이 도구는 Google 서드 파티 APK 투명성 로그를 쿼리하여 패키지가 포함되어 있는지 확인합니다.

이 도구를 사용하려면 먼저 저장소를 로컬 컴퓨터에 클론하세요.

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

인증자의 소스 코드는 android-binary-transparency 저장소 내에서 찾을 수 있습니다.

인증을 위한 페이로드 구성

추출된 APK를 인증하려면 APK 자체에서 파생된 정보를 사용하여 로그 페이로드를 구성해야 합니다.

시작하기 전에 기기에서 USB 디버깅을 사용 설정하여 adb 연결을 허용하세요.

다음으로 기기에서 설치된 APK를 찾습니다. 이 가이드에서는 Google Play 서비스 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 1개와 여러 분할 APK가 설치되어 있음을 나타냅니다 com.google.android.gms. 분할 APK의 정확한 수는 기기의 구성에 따라 다릅니다. 각 분할 APK는 기본 APK와 동일한 패키지 이름과 버전 코드를 공유합니다.

다음 명령어를 사용하여 Android 기기에서 컴퓨터로 나열된 APK를 다운로드합니다 (실제 파일 경로는 다를 수 있음).

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

이제 로그 콘텐츠 섹션에 설명된 대로 형식이 지정된 로그 페이로드를 구성하는 데 필요한 모든 정보가 있습니다. 결과에서 해시 하나를 예시로 선택하면 (모든 분할 APK의 해시를 인증해야 함) 로그 페이로드는 다음과 같습니다.

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

파일 끝에 줄 바꿈 문자를 포함해야 합니다. 이 콘텐츠를 payload.txt와 같은 파일에 저장하여 나중에 verifier 도구와 함께 사용합니다.

패키지 포함 인증 (포함 증명)

페이로드를 구성했으므로 이제 패키지가 투명성 로그에 포함되어 있는지 확인할 수 있습니다. 이전에 클론한 android-binary-transparency 저장소에서 포함 증명 도구를 빌드합니다.

go build cmd/verifier/verifier.go

이렇게 하면 해당 디렉터리에 verifier라는 실행 파일이 생성됩니다. 페이로드 경로를 제공하고 로그 유형을 지정하여 인증자를 실행합니다.

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

인증자는 체크포인트와 로그 콘텐츠 (타일 디렉터리에서)를 사용하여 APK 페이로드가 투명성 로그에 있는지 확인하고 Google에서 게시했음을 확인합니다.

명령어는 stderr에 출력합니다.

  • 패키지가 로그에 포함되어 있으면 OK. inclusion check success!입니다.
  • 포함되어 있지 않으면 FAILURE입니다.

기기의 모든 패키지 자동 인증

기기에 사전 설치될 수 있는 Google 앱의 수를 고려할 때 각 앱을 열거하고 포함 증명을 개별적으로 실행하는 것은 지루할 수 있습니다.

기기에 현재 설치된 모든 패키지를 감지하고 측정할 수 있는 Uraniborg라는 자동화된 도구를 제공합니다. 이 도구는 출력을 verifier 도구에 직접 제공하므로 한 단계로 기기의 모든 앱의 투명성을 검색하고 인증할 수 있습니다.

이 자동화된 워크플로를 사용하려면 Android 기기가 ADB를 통해 컴퓨터에 연결되어 있어야 합니다. Uraniborg 소스 코드도 android-binary-transparency 저장소에 포함되어 있습니다.

scripts/python 디렉터리에 있는 automate_observation.py 스크립트를 실행합니다.

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 값은 패키지가 투명성 로그에 대해 암호화 방식으로 인증되어 로그의 주장을 준수함을 나타냅니다.