Halaman ini menjelaskan cara menafsirkan dan menggunakan verdict integritas yang ditampilkan. Baik Anda membuat permintaan API standar maupun klasik, verdict integritas ditampilkan dalam format yang sama dengan konten serupa. Verdict integritas menyampaikan informasi tentang validitas perangkat, aplikasi, dan akun. Server aplikasi Anda dapat menggunakan payload yang dihasilkan dalam verdict yang telah didekripsi dan diverifikasi guna menentukan cara terbaik untuk melanjutkan dengan tindakan atau permintaan tertentu di aplikasi Anda.
Format verdict integritas yang ditampilkan
Payload berupa JSON teks biasa dan berisi sinyal integritas bersama informasi yang disediakan developer.
Berikut adalah struktur payload umum:
{ requestDetails: { ... } appIntegrity: { ... } deviceIntegrity: { ... } accountDetails: { ... } environmentDetails: { ... } }
Anda harus memastikan terlebih dahulu bahwa nilai di kolom requestDetails
cocok dengan nilai
dari permintaan asli sebelum memeriksa setiap verdict integritas. Bagian berikut
menjelaskan setiap kolom secara lebih mendetail.
Kolom detail permintaan
Kolom requestDetails
berisi informasi tentang permintaan, termasuk
informasi yang disediakan developer di requestHash
untuk permintaan standar dan
nonce
untuk permintaan klasik.
Untuk permintaan API standar:
requestDetails: { // Application package name this attestation was requested for. // Note that this field might be spoofed in the middle of the request. requestPackageName: "com.package.name" // Request hash provided by the developer. requestHash: "aGVsbG8gd29scmQgdGhlcmU" // The timestamp in milliseconds when the integrity token // was prepared (computed on the server). timestampMillis: "1675655009345" }
Nilai ini harus cocok dengan permintaan asal. Oleh karena itu, verifikasi
bagian requestDetails
payload JSON dengan memastikan bahwa
requestPackageName
dan requestHash
cocok dengan yang dikirim dalam permintaan
asli, seperti yang ditunjukkan dalam cuplikan kode:
Kotlin
val requestDetails = JSONObject(payload).getJSONObject("requestDetails") val requestPackageName = requestDetails.getString("requestPackageName") val requestHash = requestDetails.getString("requestHash") val timestampMillis = requestDetails.getLong("timestampMillis") val currentTimestampMillis = ... // Ensure the token is from your app. if (!requestPackageName.equals(expectedPackageName) // Ensure the token is for this specific request || !requestHash.equals(expectedRequestHash) // Ensure the freshness of the token. || currentTimestampMillis - timestampMillis > ALLOWED_WINDOW_MILLIS) { // The token is invalid! See below for further checks. ... }
Java
RequestDetails requestDetails = decodeIntegrityTokenResponse .getTokenPayloadExternal() .getRequestDetails(); String requestPackageName = requestDetails.getRequestPackageName(); String requestHash = requestDetails.getRequestHash(); long timestampMillis = requestDetails.getTimestampMillis(); long currentTimestampMillis = ...; // Ensure the token is from your app. if (!requestPackageName.equals(expectedPackageName) // Ensure the token is for this specific request. || !requestHash.equals(expectedRequestHash) // Ensure the freshness of the token. || currentTimestampMillis - timestampMillis > ALLOWED_WINDOW_MILLIS) { // The token is invalid! See below for further checks. ... }
Untuk permintaan API klasik:
requestDetails: { // Application package name this attestation was requested for. // Note that this field might be spoofed in the middle of the // request. requestPackageName: "com.package.name" // base64-encoded URL-safe no-wrap nonce provided by the developer. nonce: "aGVsbG8gd29scmQgdGhlcmU" // The timestamp in milliseconds when the request was made // (computed on the server). timestampMillis: "1617893780" }
Nilai ini harus cocok dengan permintaan asal. Oleh karena itu, verifikasi
bagian requestDetails
payload JSON dengan memastikan bahwa
requestPackageName
dan nonce
cocok dengan yang dikirim dalam permintaan asli, seperti
yang ditunjukkan dalam cuplikan kode:
Kotlin
val requestDetails = JSONObject(payload).getJSONObject("requestDetails") val requestPackageName = requestDetails.getString("requestPackageName") val nonce = requestDetails.getString("nonce") val timestampMillis = requestDetails.getLong("timestampMillis") val currentTimestampMillis = ... // Ensure the token is from your app. if (!requestPackageName.equals(expectedPackageName) // Ensure the token is for this specific request. See 'Generate a nonce' // section of the doc on how to store/compute the expected nonce. || !nonce.equals(expectedNonce) // Ensure the freshness of the token. || currentTimestampMillis - timestampMillis > ALLOWED_WINDOW_MILLIS) { // The token is invalid! See below for further checks. ... }
Java
JSONObject requestDetails = new JSONObject(payload).getJSONObject("requestDetails"); String requestPackageName = requestDetails.getString("requestPackageName"); String nonce = requestDetails.getString("nonce"); long timestampMillis = requestDetails.getLong("timestampMillis"); long currentTimestampMillis = ...; // Ensure the token is from your app. if (!requestPackageName.equals(expectedPackageName) // Ensure the token is for this specific request. See 'Generate a nonce' // section of the doc on how to store/compute the expected nonce. || !nonce.equals(expectedNonce) // Ensure the freshness of the token. || currentTimestampMillis - timestampMillis > ALLOWED_WINDOW_MILLIS) { // The token is invalid! See below for further checks. ... }
Kolom integritas aplikasi
Kolom appIntegrity
berisi informasi terkait paket.
appIntegrity: { // PLAY_RECOGNIZED, UNRECOGNIZED_VERSION, or UNEVALUATED. appRecognitionVerdict: "PLAY_RECOGNIZED" // The package name of the app. // This field is populated iff appRecognitionVerdict != UNEVALUATED. packageName: "com.package.name" // The sha256 digest of app certificates (base64-encoded URL-safe). // This field is populated iff appRecognitionVerdict != UNEVALUATED. certificateSha256Digest: ["6a6a1474b5cbbb2b1aa57e0bc3"] // The version of the app. // This field is populated iff appRecognitionVerdict != UNEVALUATED. versionCode: "42" }
appRecognitionVerdict
dapat memiliki nilai berikut:
PLAY_RECOGNIZED
- Aplikasi dan sertifikat cocok dengan versi yang didistribusikan oleh Google Play.
UNRECOGNIZED_VERSION
- Nama paket atau sertifikat tidak cocok dengan data Google Play.
UNEVALUATED
- Integritas aplikasi tidak dievaluasi. Persyaratan yang diperlukan tidak terpenuhi, seperti perangkat tidak cukup tepercaya.
Untuk memastikan bahwa token dibuat oleh aplikasi yang dibuat oleh Anda, pastikan integritas aplikasi seperti yang diharapkan, seperti yang ditampilkan dalam cuplikan kode berikut:
Kotlin
val appIntegrity = JSONObject(payload).getJSONObject("appIntegrity") val appRecognitionVerdict = appIntegrity.getString("appRecognitionVerdict") if (appRecognitionVerdict == "PLAY_RECOGNIZED") { // Looks good! }
Java
JSONObject appIntegrity = new JSONObject(payload).getJSONObject("appIntegrity"); String appRecognitionVerdict = appIntegrity.getString("appRecognitionVerdict"); if (appRecognitionVerdict.equals("PLAY_RECOGNIZED")) { // Looks good! }
Anda juga dapat memeriksa nama paket aplikasi, versi aplikasi, dan sertifikat aplikasi secara manual.
Kolom integritas perangkat
Kolom deviceIntegrity
dapat berisi satu nilai,
deviceRecognitionVerdict
, yang memiliki satu atau beberapa label yang merepresentasikan seberapa baik
perangkat dapat menerapkan integritas aplikasi. Jika perangkat tidak memenuhi kriteria label apa pun,
kolom deviceIntegrity
akan kosong.
deviceIntegrity: { // "MEETS_DEVICE_INTEGRITY" is one of several possible values. deviceRecognitionVerdict: ["MEETS_DEVICE_INTEGRITY"] }
Secara default, deviceRecognitionVerdict
dapat berisi hal berikut:
MEETS_DEVICE_INTEGRITY
- Aplikasi berjalan di perangkat yang didukung Android dengan layanan Google Play. Perangkat lulus pemeriksaan integritas sistem dan memenuhi persyaratan kompatibilitas Android.
- Kosong (nilai kosong)
- Aplikasi berjalan pada perangkat yang memiliki tanda-tanda serangan (seperti hooking API) atau penyusupan sistem (seperti di-root), atau aplikasi tidak berjalan pada perangkat fisik (seperti emulator yang tidak lulus pemeriksaan integritas Google Play).
Untuk memastikan bahwa token berasal dari perangkat tepercaya, pastikan
deviceRecognitionVerdict
sesuai dengan yang diharapkan, seperti ditunjukkan dalam cuplikan
kode berikut:
Kotlin
val deviceIntegrity = JSONObject(payload).getJSONObject("deviceIntegrity") val deviceRecognitionVerdict = if (deviceIntegrity.has("deviceRecognitionVerdict")) { deviceIntegrity.getJSONArray("deviceRecognitionVerdict").toString() } else { "" } if (deviceRecognitionVerdict.contains("MEETS_DEVICE_INTEGRITY")) { // Looks good! }
Java
JSONObject deviceIntegrity = new JSONObject(payload).getJSONObject("deviceIntegrity"); String deviceRecognitionVerdict = deviceIntegrity.has("deviceRecognitionVerdict") ? deviceIntegrity.getJSONArray("deviceRecognitionVerdict").toString() : ""; if (deviceRecognitionVerdict.contains("MEETS_DEVICE_INTEGRITY")) { // Looks good! }
Jika Anda mengalami masalah dengan pengujian perangkat memenuhi integritas perangkat, pastikan ROM pabrik sudah diinstal (misalnya, dengan mereset perangkat) dan bootloader terkunci. Anda juga dapat membuat pengujian Play Integrity API di Konsol Play.
Label perangkat bersyarat
Jika aplikasi Anda dirilis ke Google Play Game untuk PC, deviceRecognitionVerdict
juga dapat berisi label berikut:
MEETS_VIRTUAL_INTEGRITY
- Aplikasi berjalan di emulator yang didukung Android dengan layanan Google Play. Emulator lulus pemeriksaan integritas sistem dan memenuhi persyaratan kompatibilitas inti Android.
Informasi perangkat opsional
Jika Anda memilih untuk menerima label
tambahan dalam verdict integritas,
deviceRecognitionVerdict
dapat memiliki label tambahan berikut:
MEETS_BASIC_INTEGRITY
- Aplikasi berjalan di perangkat yang telah lulus pemeriksaan integritas sistem dasar. Perangkat mungkin tidak memenuhi persyaratan kompatibilitas Android dan mungkin tidak disetujui untuk menjalankan layanan Google Play. Misalnya, perangkat mungkin menjalankan versi Android yang tidak dikenal, mungkin memiliki bootloader yang tidak terkunci, atau mungkin belum disertifikasi oleh produsen.
MEETS_STRONG_INTEGRITY
- Aplikasi tersebut berjalan di perangkat yang didukung Android dengan layanan Google Play dan memiliki jaminan kuat atas integritas sistem seperti bukti integritas booting yang didukung hardware. Perangkat lulus pemeriksaan integritas sistem dan memenuhi persyaratan kompatibilitas Android.
Satu perangkat akan menampilkan beberapa label perangkat dalam verdict integritas perangkat jika setiap kriteria label terpenuhi.
Aktivitas perangkat terbaru (beta)
Anda juga dapat ikut serta dalam aktivitas perangkat terbaru, yang memberi tahu berapa kali aplikasi Anda meminta token integritas di perangkat tertentu dalam satu jam terakhir. Anda dapat menggunakan aktivitas perangkat terbaru untuk melindungi aplikasi dari perangkat hiperaktif yang tidak terduga yang mungkin merupakan indikasi serangan aktif. Anda dapat menentukan seberapa besar tingkat kepercayaan terhadap setiap level aktivitas perangkat terbaru berdasarkan perkiraan jumlah aplikasi Anda diinstal di perangkat standar untuk meminta token integritas setiap jamnya.
Jika Anda memilih untuk menerima recentDeviceActivity
, kolom deviceIntegrity
akan memiliki dua nilai:
deviceIntegrity: { deviceRecognitionVerdict: ["MEETS_DEVICE_INTEGRITY"] recentDeviceActivity: { // "LEVEL_2" is one of several possible values. deviceActivityLevel: "LEVEL_2" } }
deviceActivityLevel
dapat memiliki salah satu nilai berikut:
LEVEL_1
- Level terendah: Aplikasi meminta 10 token integritas atau kurang di perangkat ini dalam satu jam terakhir.
LEVEL_2
- Aplikasi meminta antara 11 dan 25 token integritas di perangkat ini dalam satu jam terakhir.
LEVEL_3
- Aplikasi meminta antara 26 dan 50 token integritas di perangkat ini dalam satu jam terakhir.
LEVEL_4
- Level tertinggi: Aplikasi meminta lebih dari 50 token integritas di perangkat ini dalam satu jam terakhir.
UNEVALUATED
Level aktivitas perangkat terbaru tidak dievaluasi. Hal ini dapat terjadi karena beberapa alasan, termasuk:
- Perangkat tidak cukup tepercaya.
- Versi aplikasi yang diinstal di perangkat tidak dikenal oleh Google Play.
- Masalah teknis pada perangkat.
Definisi level hanya perkiraan dan dapat berubah sewaktu-waktu.
Kolom detail akun
Kolom accountDetails
berisi satu nilai, appLicensingVerdict
, yang
menunjukkan status pemberian lisensi aplikasi.
accountDetails: { // This field can be LICENSED, UNLICENSED, or UNEVALUATED. appLicensingVerdict: "LICENSED" }
appLicensingVerdict
dapat memiliki salah satu nilai berikut:
LICENSED
- Pengguna memiliki hak aplikasi. Dengan kata lain, pengguna menginstal atau membeli aplikasi Anda di Google Play.
UNLICENSED
- Pengguna tidak memiliki hak aplikasi. Hal ini terjadi saat, misalnya, pengguna melakukan sideload pada aplikasi Anda atau tidak menginstalnya dari Google Play. Anda dapat menampilkan dialog GET_LicenseD kepada pengguna untuk memperbaiki masalah ini.
UNEVALUATED
Detail pemberian lisensi tidak dievaluasi karena persyaratan yang diperlukan tidak terpenuhi.
Hal ini dapat terjadi karena beberapa alasan, termasuk:
- Perangkat tidak cukup tepercaya.
- Versi aplikasi yang diinstal di perangkat tidak dikenal oleh Google Play.
- Pengguna tidak login ke Google Play.
Untuk memeriksa apakah pengguna memiliki hak aplikasi untuk aplikasi Anda, verifikasi bahwa
appLicensingVerdict
sudah sesuai harapan, seperti yang ditunjukkan dalam cuplikan kode berikut:
Kotlin
val accountDetails = JSONObject(payload).getJSONObject("accountDetails") val appLicensingVerdict = accountDetails.getString("appLicensingVerdict") if (appLicensingVerdict == "LICENSED") { // Looks good! }
Java
JSONObject accountDetails = new JSONObject(payload).getJSONObject("accountDetails"); String appLicensingVerdict = accountDetails.getString("appLicensingVerdict"); if (appLicensingVerdict.equals("LICENSED")) { // Looks good! }
Kolom detail lingkungan
Jika Anda telah memilih ikut serta dalam verdict Play Protect di Konsol Google Play,
respons API Anda akan menyertakan kolom environmentDetails
. Kolom
environmentDetails
berisi satu nilai, playProtectVerdict
,
yang memberikan informasi tentang Google Play Protect di perangkat.
environmentDetails: { playProtectVerdict: "NO_ISSUES" }
playProtectVerdict
dapat memiliki salah satu nilai berikut:
NO_ISSUES
- Play Protect diaktifkan dan tidak menemukan masalah aplikasi apa pun di perangkat.
NO_DATA
- Play Protect diaktifkan, tetapi belum ada pemindaian yang dilakukan. Perangkat atau aplikasi Play Store mungkin baru saja direset.
POSSIBLE_RISK
- Play Protect dinonaktifkan.
MEDIUM_RISK
- Play Protect diaktifkan dan telah menemukan aplikasi yang berpotensi membahayakan diinstal di perangkat.
HIGH_RISK
- Play Protect diaktifkan dan telah menemukan aplikasi berbahaya diinstal di perangkat.
UNEVALUATED
Verdict Play Protect tidak dievaluasi.
Hal ini dapat terjadi karena beberapa alasan, termasuk:
- Perangkat tidak cukup tepercaya.
- Khusus game: Akun pengguna bukan
LICENSED
.
Panduan cara menggunakan verdict Play Protect
Server backend aplikasi Anda dapat menentukan cara bertindak berdasarkan verdict berdasarkan toleransi risiko Anda. Berikut adalah beberapa saran dan tindakan yang dapat dilakukan pengguna:
NO_ISSUES
- Play Protect diaktifkan dan belum menemukan masalah apa pun sehingga tidak ada tindakan yang perlu dilakukan pengguna.
POSSIBLE_RISK
danNO_DATA
- Jika menerima verdict ini, minta pengguna untuk memeriksa apakah Play Protect sudah diaktifkan
dan telah melakukan pemindaian.
NO_DATA
hanya akan muncul dalam situasi yang jarang terjadi. MEDIUM_RISK
danHIGH_RISK
- Bergantung pada toleransi risiko, Anda dapat meminta pengguna untuk meluncurkan Play Protect dan mengambil tindakan terhadap peringatan Play Protect. Jika pengguna tidak dapat memenuhi persyaratan ini, Anda dapat memblokirnya dari tindakan server.