In questa pagina viene descritto come interpretare e utilizzare l'integrità restituita verdetto. Indipendentemente dal fatto che si effettui una richiesta API standard o classica, l'integrità l'esito viene restituito nello stesso formato con contenuti simili. L'integrità l'esito comunica informazioni sulla validità di dispositivi, app e . Il server dell'app può utilizzare il payload risultante in un file decriptato, un esito verificato per stabilire come procedere al meglio con una determinata azione o richiesta nell'app.
Formato dell'esito relativo all'integrità restituito
Il payload è in formato JSON in testo normale e contiene indicatori di integrità fornite dallo sviluppatore.
La struttura generale del payload è la seguente:
{ requestDetails: { ... } appIntegrity: { ... } deviceIntegrity: { ... } accountDetails: { ... } environmentDetails: { ... } }
Devi prima verificare che i valori nel campo requestDetails
corrispondano a questi
della richiesta originale prima di controllare ogni esito relativo all'integrità. Le seguenti
ogni campo viene descritto in modo più dettagliato.
Campo dettagli richiesta
Il campo requestDetails
contiene informazioni sulla richiesta, tra cui:
le informazioni fornite dallo sviluppatore nel requestHash
per le richieste standard e
nonce
per le richieste classiche.
Per le richieste API standard:
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 requested. timestampMillis: "1675655009345" }
Questi valori devono corrispondere a quelli della richiesta originale. Pertanto, verifica
requestDetails
parte del payload JSON, assicurandoti che
requestPackageName
e requestHash
corrispondono a quanto inviato nell'originale
come mostrato nello snippet di codice riportato di seguito:
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. ... }
Per le richieste API classiche:
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" }
Questi valori devono corrispondere a quelli della richiesta originale. Pertanto, verifica
requestDetails
parte del payload JSON, assicurandoti che
requestPackageName
e nonce
corrispondono a quanto inviato nella richiesta originale, come
mostrato nel seguente snippet di codice:
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. ... }
Campo Integrità dell'applicazione
Il campo appIntegrity
contiene informazioni relative al pacchetto.
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
può avere i seguenti valori:
PLAY_RECOGNIZED
- L'app e il certificato corrispondono alle versioni distribuite da su Google Play.
UNRECOGNIZED_VERSION
- Il nome del certificato o del pacchetto non corrisponde a Google Riproduci i record.
UNEVALUATED
- L'integrità dell'applicazione non è stata valutata. Un requisito necessario perso, ad esempio perché il dispositivo non è abbastanza attendibile.
Per assicurarti che il token sia stato generato da un'app creata da te, verifica che l'integrità dell'applicazione sia quella prevista, come mostrato nel codice che segue snippet:
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! }
Puoi anche controllare il nome del pacchetto e la versione dell'app e i certificati dell'app manualmente.
Campo Integrità del dispositivo
Il campo deviceIntegrity
può contenere un singolo valore,
deviceRecognitionVerdict
, che ha una o più etichette che rappresentano l'efficacia di una
dispositivo può imporre l'integrità dell'app. Se un dispositivo non soddisfa i criteri di
etichette, il campo deviceIntegrity
è vuoto.
deviceIntegrity: { // "MEETS_DEVICE_INTEGRITY" is one of several possible values. deviceRecognitionVerdict: ["MEETS_DEVICE_INTEGRITY"] }
Per impostazione predefinita, deviceRecognitionVerdict
può contenere quanto segue:
MEETS_DEVICE_INTEGRITY
- L'app viene eseguita su un dispositivo Android con Google Play Services. Il dispositivo supera i controlli relativi all'integrità del sistema e soddisfa Requisiti di compatibilità di Android.
- Vuoto (valore vuoto)
- L'app è in esecuzione su un dispositivo che presenta segni di attacchi (come l'hook delle API) o compromissione del sistema (ad esempio il rooting) oppure l'app non è in esecuzione su un dispositivo fisico (ad esempio un emulatore che non superare i controlli relativi all'integrità di Google Play).
Per assicurarti che il token provenga da un dispositivo attendibile, verifica
deviceRecognitionVerdict
è come previsto, come mostrato nel seguente codice
snippet:
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! }
Se hai problemi relativi all'integrità del dispositivo per riunioni, assicurati che la ROM di fabbrica sia installata (ad esempio ripristinando il dispositivo) e che il bootloader sia bloccato. Puoi anche creare test dell'API Play Integrity nella tua Play Console.
Etichette condizionali dei dispositivi
Se la tua app viene rilasciata per Google Play Giochi per PC, i
deviceRecognitionVerdict
può anche contenere la seguente etichetta:
MEETS_VIRTUAL_INTEGRITY
- L'app è installata su un emulatore Android con Google Play Services. L'emulatore supera i controlli relativi all'integrità del sistema e soddisfa requisiti fondamentali di compatibilità con Android.
Informazioni facoltative del dispositivo
Se attivi la ricezione di ulteriori
etichette nell'esito relativo all'integrità,
deviceRecognitionVerdict
può contenere le seguenti etichette aggiuntive:
MEETS_BASIC_INTEGRITY
- L'app è in esecuzione su un dispositivo che supera i test di base e controlli di integrità del sistema. Il dispositivo potrebbe non soddisfare la compatibilità Android requisiti e potrebbe non essere approvata per eseguire Google Play Services. Per esempio, sul dispositivo potrebbe essere in esecuzione una versione di Android non riconosciuta, disponi di un bootloader sbloccato o potrebbe non essere stato certificato dal produttore.
MEETS_STRONG_INTEGRITY
- L'app viene eseguita su un dispositivo Android con Google Play Services e ha una solida garanzia di integrità del sistema, ad esempio: una prova dell'integrità di avvio supportata dall'hardware. Il dispositivo supera la verifica del sistema verifica l'integrità e soddisfi i requisiti di compatibilità di Android.
Un singolo dispositivo restituirà più etichette del dispositivo nell'integrità del dispositivo l'esito se viene soddisfatto tutti i criteri dell'etichetta.
Attività del dispositivo recente
Puoi anche attivare le attività recenti del dispositivo, che ti indicano Molte volte la tua app ha richiesto un token di integrità su un dispositivo specifico. nell'ultima ora. Puoi usare l'attività recente del dispositivo per proteggere la tua app da dispositivi inaspettati e iperattivi che potrebbero indicare un attacco attivo. Puoi decidere il livello di attendibilità di ogni livello di attività recente del dispositivo in base a come molte volte ti aspetti che l'app installata su un dispositivo tipico richieda un il token di integrità ogni ora.
Se attivi la ricezione di recentDeviceActivity
, il campo deviceIntegrity
avrà due valori:
deviceIntegrity: { deviceRecognitionVerdict: ["MEETS_DEVICE_INTEGRITY"] recentDeviceActivity: { // "LEVEL_2" is one of several possible values. deviceActivityLevel: "LEVEL_2" } }
Le definizioni di deviceActivityLevel
differiscono da una modalità all'altra e possono avere
uno dei seguenti valori:
Livello di attività recente del dispositivo | Richieste di token di integrità dell'API standard su questo dispositivo nell'ultima ora per app | Richieste di token di integrità dell'API classiche su questo dispositivo nell'ultima ora per app |
---|---|---|
LEVEL_1 (valore più basso) |
10 o meno | 5 o meno |
LEVEL_2 |
Tra 11 e 25 | Tra 6 e 10 |
LEVEL_3 |
Tra 26 e 50 | Tra 11 e 15 |
LEVEL_4 (valore più alto) |
Più di 50 | Più di 15 |
UNEVALUATED |
L'attività recente del dispositivo non è stata valutata. Ciò può accadere
perché:
|
Campo dettagli account
Il campo accountDetails
contiene un singolo valore, appLicensingVerdict
, che
rappresenta lo stato di licenza dell'app Google Play per l'account utente di
connesso sul dispositivo. Se l'account utente dispone della licenza Google Play per l'app,
significa che è stato scaricato o acquistato su Google Play.
accountDetails: { // This field can be LICENSED, UNLICENSED, or UNEVALUATED. appLicensingVerdict: "LICENSED" }
appLicensingVerdict
può avere uno dei seguenti valori:
LICENSED
- L'utente dispone di autorizzazione per l'app. In altre parole, l'utente ha installato o acquistato la tua app su Google Play.
UNLICENSED
- L'utente non dispone di autorizzazione per l'app. Questo accade quando, ad Ad esempio, l'utente installa la tua app tramite sideload o non la acquisisce da Google Play. Per risolvere il problema, puoi mostrare agli utenti la finestra di dialogo GET_LICENSED.
UNEVALUATED
I dettagli relativi alle licenze non sono stati valutati perché era necessario requisito non soddisfatto.
Questo potrebbe accadere per diversi motivi, tra cui:
- Il dispositivo non è abbastanza attendibile.
- La versione dell'app installata sul dispositivo non è nota a Google Gioca.
- L'utente non ha eseguito l'accesso a Google Play.
Per controllare che l'utente disponga di diritti per l'app in questione, verifica che le
appLicensingVerdict
è come previsto, come mostrato nel seguente snippet di codice:
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! }
Campo dettagli ambiente
Puoi anche attivare indicatori aggiuntivi sull'ambiente. Accesso alle app indica alla tua app se sono in esecuzione altre app che potrebbero essere utilizzate per acquisire lo schermo, visualizzare overlay o controllare il dispositivo. Play Protect indica se Google Play Protect è attivo sul dispositivo e se ha rilevato malware noto.
Se hai attivato l'esito del rischio di accesso alle app o l'esito Play Protect
in Google Play Console, la risposta dell'API includerà
campo environmentDetails
. Il campo environmentDetails
può contenere due
valori, appAccessRiskVerdict
e playProtectVerdict
.
Esito del rischio di accesso all'app (beta)
Una volta attivato, il campo environmentDetails
nell'API Play Integrity
conterrà
il nuovo esito del rischio di accesso all'app.
{
requestDetails: { ... }
appIntegrity: { ... }
deviceIntegrity: { ... }
accountDetails: { ... }
environmentDetails: {
appAccessRiskVerdict: {
// This field contains one or more responses, for example the following.
appsDetected: ["KNOWN_INSTALLED", "UNKNOWN_INSTALLED", "UNKNOWN_CAPTURING"]
}
}
}
Se è stato valutato il rischio di accesso all'app, appAccessRiskVerdict
contiene il campo
appsDetected
con una o più risposte. Queste risposte rientrano in uno dei seguenti
due gruppi seguenti, a seconda dell'origine di installazione delle app rilevate:
App di sistema o di Google Play: app installate da Google Play o precaricate dal produttore del dispositivo sulla partizione di sistema del dispositivo (identificato con
FLAG_SYSTEM
). Le risposte per queste app sono precedute dal prefissoKNOWN_
.Altre app: app non installate da Google Play. Ciò esclude app precaricate sulla partizione di sistema dal produttore del dispositivo. Risposte per queste app sono preceduti dal prefisso
UNKNOWN_
.
È possibile restituire le seguenti risposte:
KNOWN_INSTALLED
,UNKNOWN_INSTALLED
- Sono presenti app installate che corrispondono all'origine di installazione corrispondente.
KNOWN_CAPTURING
,UNKNOWN_CAPTURING
- Sono presenti app in esecuzione con autorizzazioni abilitate che potrebbero essere utilizzate per visualizzare la schermata mentre l'app è in esecuzione. Sono escluse le istanze verificate i servizi di accessibilità noti a Google Play in esecuzione sul dispositivo.
KNOWN_CONTROLLING
,UNKNOWN_CONTROLLING
- Sono presenti app in esecuzione con autorizzazioni abilitate che potrebbero essere utilizzate per controllare il dispositivo, controllare direttamente gli ingressi nell'app e potrebbe essere utilizzati per acquisire input e output della tua app. Sono escluse le istanze verificate i servizi di accessibilità noti a Google Play in esecuzione sul dispositivo.
KNOWN_OVERLAYS
,UNKNOWN_OVERLAYS
- Sono presenti app in esecuzione con autorizzazioni abilitate che potrebbero essere utilizzate per visualizzare overlay sulla tua app. Esclude qualsiasi accessibilità verificata servizi noti a Google Play in esecuzione sul dispositivo.
- EMPTY (valore vuoto)
Il rischio di accesso all'app non viene valutato se non è stato soddisfatto un requisito necessario. Nel In questo caso, il campo
appAccessRiskVerdict
è vuoto. Questo può accadere per per diversi motivi, tra cui:- Il dispositivo non è abbastanza attendibile.
- Il fattore di forma del dispositivo non è uno smartphone, un tablet o un dispositivo pieghevole.
- Sul dispositivo non è installato Android 6 (livello API 23) o versioni successive.
- La versione dell'app installata sul dispositivo non è nota a Google Play.
- La versione del Google Play Store sul dispositivo è obsoleta.
- Solo giochi: l'account utente non ha una licenza Google Play per il gioco.
- È stata usata una richiesta standard con il parametro
verdictOptOut
. - È stata usata una richiesta standard con una versione della libreria API Play Integrity che non supporta ancora il rischio di accesso all'app per le richieste standard.
Il rischio di accesso all'app esclude automaticamente i servizi di accessibilità verificati che
siano stati sottoposti a una revisione migliorata dell'accessibilità di Google Play (installata
qualsiasi store sul dispositivo). "Escluso" significa che l'accessibilità verificata
in esecuzione sul dispositivo non restituiranno un'acquisizione, un controllo
overlay la risposta nell'esito del rischio di accesso all'app. Per richiedere una versione avanzata di Google
Riproduci la revisione dell'accessibilità per la tua app di accessibilità, pubblicala su Google
Riproduci assicurandoti che il flag isAccessibilityTool
della tua app sia impostato su true in
il file manifest dell'app o richiedi una revisione.
La tabella seguente fornisce alcuni esempi di esiti e il relativo significato (questo non elenca tutti i risultati possibili):
Esempio di risposta sull'esito del rischio di accesso all'app | Interpretazione |
---|---|
appsDetected: ["KNOWN_INSTALLED"]
|
Sono presenti solo app installate che sono riconosciute da Google Play o precaricate nella partizione di sistema dal produttore del dispositivo. Non sono presenti app in esecuzione che comporterebbero l'acquisizione, il controllo o gli esiti in overlay. |
appsDetected: ["KNOWN_INSTALLED", "UNKNOWN_INSTALLED", "UNKNOWN_CAPTURING"]
|
Esistono app installate da Google Play o precaricate sulla partizione di sistema dal produttore del dispositivo. Ci sono altre app in esecuzione e con autorizzazioni attive che potrebbero essere usate per visualizzare lo schermo o acquisire altri input e output. |
appsDetected: ["KNOWN_INSTALLED", "KNOWN_CAPTURING", "UNKNOWN_INSTALLED", "UNKNOWN_CONTROLLING"]
|
È in esecuzione la riproduzione o un sistema con autorizzazioni attivate che potrebbero essere usate per visualizzare la schermata o acquisire altri input e output. Esistono anche altre app in esecuzione con autorizzazioni attivate che possono essere usate per controllare il dispositivo e controllare direttamente gli ingressi nella tua app. |
appAccessRiskVerdict: {}
|
Il rischio di accesso all'app non viene valutato perché non è stato soddisfatto un requisito necessario. Ad esempio, il dispositivo non era abbastanza attendibile. |
A seconda del livello di rischio, puoi decidere quale combinazione di esiti accettabile per procedere e sugli esiti sui quali vuoi prendere provvedimenti. La il seguente snippet di codice illustra un esempio di verifica che non siano presenti App in esecuzione che potrebbero acquisire la schermata o controllare la tua app:
Kotlin
val environmentDetails = JSONObject(payload).getJSONObject("environmentDetails") val appAccessRiskVerdict = environmentDetails.getJSONObject("appAccessRiskVerdict") if (appAccessRiskVerdict.has("appsDetected")) { val appsDetected = appAccessRiskVerdict.getJSONArray("appsDetected").toString() if (!appsDetected.contains("CAPTURING") && !appsDetected.contains("CONTROLLING")) { // Looks good! } }
Java
JSONObject environmentDetails = new JSONObject(payload).getJSONObject("environmentDetails"); JSONObject appAccessRiskVerdict = environmentDetails.getJSONObject("appAccessRiskVerdict"); if (appAccessRiskVerdict.has("appsDetected")) { String appsDetected = appAccessRiskVerdict.getJSONArray("appsDetected").toString() if (!appsDetected.contains("CAPTURING") && !appsDetected.contains("CONTROLLING")) { // Looks good! } }
Risolvi gli esiti del rischio di accesso all'app
A seconda del tuo livello di rischio, puoi decidere quali esiti del rischio di accesso alle app su cui vuoi intervenire prima di permettere all'utente di completare una richiesta o un'azione. Esistono dei messaggi facoltativi di Google Play che puoi mostrare all'utente dopo controllare l'esito del rischio di accesso all'app. Puoi mostrare CLOSE_UNKNOWN_ACCESS_RISK per chiedere all'utente di chiudere le app sconosciute che causano l'esito del rischio di accesso all'app oppure puoi mostrare CLOSE_ALL_ACCESS_RISK per chiedere all'utente di chiudere tutte le app (note e sconosciute) causando l'esito del rischio di accesso all'app.
Esito Play Protect
Una volta attivato, il campo environmentDetails
nell'API Play Integrity
conterrà
l'esito di Play Protect:
environmentDetails: {
playProtectVerdict: "NO_ISSUES"
}
playProtectVerdict
può avere uno dei seguenti valori:
NO_ISSUES
- Play Protect è attivo e non ha rilevato alcun problema con l'app sul dispositivo.
NO_DATA
- Play Protect è attivo, ma non è stata ancora eseguita alcuna scansione. Il dispositivo o l'app Play Store potrebbe essere stata reimpostata di recente.
POSSIBLE_RISK
- Play Protect è disattivato.
MEDIUM_RISK
- Play Protect è attivo e ha trovato app potenzialmente dannose installate sul dispositivo.
HIGH_RISK
- Play Protect è attivo e ha trovato app pericolose installate sul .
UNEVALUATED
L'esito di Play Protect non è stato valutato.
Questo potrebbe accadere per diversi motivi, tra cui:
- Il dispositivo non è abbastanza attendibile.
- Solo giochi: l'account utente non ha una licenza Google Play per il gioco.
Indicazioni sull'utilizzo dell'esito di Play Protect
Il server di backend dell'app può decidere come agire in base all'esito in base la tua tolleranza al rischio. Ecco alcuni suggerimenti e potenziali azioni degli utenti:
NO_ISSUES
- Play Protect è attivo e non ha rilevato problemi, quindi non è richiesta alcuna azione da parte dell'utente.
POSSIBLE_RISK
eNO_DATA
- Quando ricevi questi esiti, chiedi all'utente di verificare che Play Protect sia attivo
e ha eseguito la scansione.
NO_DATA
deve apparire solo in rare circostanze. MEDIUM_RISK
eHIGH_RISK
- A seconda della tua tolleranza al rischio, puoi chiedere all'utente di avviare Google Play Protect e prendi provvedimenti in merito agli avvisi di Play Protect. Se l'utente non riesce a completare per questi requisiti, potresti impedire loro di eseguire l'azione del server.