Auf dieser Seite wird beschrieben, wie Sie das zurückgegebene Integritätsergebnis interpretieren und damit arbeiten. Unabhängig davon, ob Sie eine Standard- oder klassische API-Anfrage stellen, wird das Integritätsergebnis im selben Format mit ähnlichem Inhalt zurückgegeben. Das Integritätsergebnis kommuniziert Informationen über die Gültigkeit von Geräten, Apps und Konten. Der Server Ihrer App kann die resultierende Nutzlast in einem entschlüsselten, bestätigten Ergebnis verwenden, um zu bestimmen, wie am besten mit einer bestimmten Aktion oder Anfrage in Ihrer App fortgefahren wird.
Format des zurückgegebenen Integritätsergebnisses
Die Nutzlast ist eine JSON-Datei im Nur-Text-Format und enthält neben den vom Entwickler bereitgestellten Informationen Integritätssignale.
Die allgemeine Nutzlaststruktur sieht so aus:
{ requestDetails: { ... } appIntegrity: { ... } deviceIntegrity: { ... } accountDetails: { ... } environmentDetails: { ... } }
Sie müssen zuerst prüfen, ob die Werte im Feld requestDetails
mit denen der ursprünglichen Anfrage übereinstimmen, bevor Sie jedes Integritätsergebnis prüfen. In den folgenden Abschnitten werden die einzelnen Felder genauer beschrieben.
Feld mit Anfragedetails
Das Feld requestDetails
enthält Informationen zur Anfrage, darunter vom Entwickler bereitgestellte Informationen in der requestHash
für Standardanfragen und der nonce
für klassische Anfragen.
Für standardmäßige API-Anfragen:
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" }
Diese Werte sollten denen der ursprünglichen Anfrage entsprechen. Prüfen Sie daher den Teil requestDetails
der JSON-Nutzlast. Dazu müssen requestPackageName
und requestHash
mit dem übereinstimmen, was in der ursprünglichen Anfrage gesendet wurde, wie im folgenden Code-Snippet gezeigt:
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. ... }
Für klassische API-Anfragen:
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" }
Diese Werte sollten denen der ursprünglichen Anfrage entsprechen. Prüfen Sie daher den Teil requestDetails
der JSON-Nutzlast. Dazu müssen requestPackageName
und nonce
mit dem übereinstimmen, was in der ursprünglichen Anfrage gesendet wurde, wie im folgenden Code-Snippet gezeigt:
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. ... }
Feld für Anwendungsintegrität
Das Feld appIntegrity
enthält paketbezogene Informationen.
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
kann die folgenden Werte haben:
PLAY_RECOGNIZED
- Die App und das Zertifikat stimmen mit den bei Google Play vertriebenen Versionen überein.
UNRECOGNIZED_VERSION
- Das Zertifikat oder der Paketname stimmt nicht mit den Google Play-Einträgen überein.
UNEVALUATED
- Die Anwendungsintegrität wurde nicht bewertet. Eine erforderliche Voraussetzung wurde nicht erfüllt, z. B. dass das Gerät nicht vertrauenswürdig genug sein muss.
Prüfen Sie, ob die Anwendungsintegrität wie im folgenden Code-Snippet erwartet wird, damit das Token von einer von Ihnen erstellten Anwendung generiert wurde:
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! }
Sie können den App-Paketnamen, die App-Version und die App-Zertifikate auch manuell prüfen.
Feld „Geräteintegrität“
Das Feld deviceIntegrity
kann den einzelnen Wert deviceRecognitionVerdict
mit einem oder mehreren Labels enthalten, die angeben, wie gut ein Gerät die App-Integrität erzwingen kann. Wenn ein Gerät die Kriterien von Labels nicht erfüllt, ist das Feld deviceIntegrity
leer.
deviceIntegrity: { // "MEETS_DEVICE_INTEGRITY" is one of several possible values. deviceRecognitionVerdict: ["MEETS_DEVICE_INTEGRITY"] }
Standardmäßig kann deviceRecognitionVerdict
Folgendes enthalten:
MEETS_DEVICE_INTEGRITY
- Die App wird auf einem Android-Gerät mit Google Play-Diensten ausgeführt. Das Gerät besteht die Systemintegritätsprüfungen und erfüllt die Android-Kompatibilitätsanforderungen.
- Leer (leerer Wert)
- Die App wird auf einem Gerät ausgeführt, das Anzeichen von Angriffen (z. B. API-Hooks) oder Systemmanipulationen (z. B. Rooting) aufweist, oder sie wird nicht auf einem physischen Gerät ausgeführt (z. B. einem Emulator, der die Google Play-Integritätsprüfungen nicht besteht).
Prüfen Sie, ob deviceRecognitionVerdict
wie erwartet funktioniert, wie im folgenden Code-Snippet gezeigt, damit das Token von einem vertrauenswürdigen Gerät stammt:
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! }
Wenn Sie Probleme mit dem Testgerät haben, das die Geräteintegrität erfüllt, prüfen Sie, ob das Werkseinstellungen installiert ist (z. B. durch Zurücksetzen des Geräts) und der Bootloader gesperrt ist. Sie können auch Play Integrity API-Tests in Ihrer Play Console erstellen.
Bedingte Gerätelabels
Wenn deine App in Google Play Spiele für PC veröffentlicht wird, kann die deviceRecognitionVerdict
auch das folgende Label enthalten:
MEETS_VIRTUAL_INTEGRITY
- Die App wird in einem Android-Emulator mit Google Play-Diensten ausgeführt. Der Emulator besteht die Systemintegritätsprüfungen und erfüllt die grundlegenden Android-Kompatibilitätsanforderungen.
Optionale Geräteinformationen
Wenn Sie zusätzliche Labels für das Integritätsergebnis aktivieren, kann deviceRecognitionVerdict
die folgenden zusätzlichen Labels enthalten:
MEETS_BASIC_INTEGRITY
- Die App wird auf einem Gerät ausgeführt, das die grundlegenden Prüfungen zur Systemintegrität bestanden hat. Das Gerät erfüllt möglicherweise nicht die Kompatibilitätsanforderungen von Android und ist möglicherweise nicht für die Ausführung von Google Play-Diensten zugelassen. Es kann beispielsweise sein, dass auf dem Gerät eine unbekannte Version von Android ausgeführt wird, ein entsperrter Bootloader installiert ist oder es nicht vom Hersteller zertifiziert wurde.
MEETS_STRONG_INTEGRITY
- Die App wird auf einem Android-Gerät mit Google Play-Diensten ausgeführt und bietet eine starke Garantie für die Systemintegrität, z. B. einen hardwaregestützten Proof of Boot-Integrität. Das Gerät besteht die Systemintegritätsprüfungen und erfüllt die Android-Kompatibilitätsanforderungen.
Für ein einzelnes Gerät werden im Geräteintegritätsergebnis mehrere Gerätelabels zurückgegeben, wenn jedes der Kriterien des Labels erfüllt ist.
Geräteaktivitäten in letzter Zeit (Beta)
Sie können auch die letzten Geräteaktivitäten aktivieren, um zu erfahren, wie oft Ihre App in der letzten Stunde ein Integritätstoken auf einem bestimmten Gerät angefordert hat. Sie können die letzte Geräteaktivität verwenden, um Ihre App vor unerwarteten, hyperaktiven Geräten zu schützen, die ein Hinweis auf einen aktiven Angriff sein könnten. Sie können entscheiden, wie oft jeder aktuellen Geräteaktivitätsstufe vertraut werden soll, je nachdem, wie oft Ihre App voraussichtlich auf einem typischen Gerät pro Stunde ein Integritätstoken anfordert.
Wenn Sie recentDeviceActivity
erhalten, hat das Feld deviceIntegrity
zwei Werte:
deviceIntegrity: { deviceRecognitionVerdict: ["MEETS_DEVICE_INTEGRITY"] recentDeviceActivity: { // "LEVEL_2" is one of several possible values. deviceActivityLevel: "LEVEL_2" } }
Die deviceActivityLevel
-Definitionen unterscheiden sich je nach Modi und können einen der folgenden Werte haben:
Aktivitätslevel des letzten Geräts | Standard-API-Anfrage | Klassische API-Anfrage |
---|---|---|
LEVEL_1 (niedrigste) |
Die App hat in der letzten Stunde maximal 10 Integritätstokens auf diesem Gerät angefordert. | Die App hat in der letzten Stunde maximal 5 Integritätstokens auf diesem Gerät angefordert. |
LEVEL_2 |
Die App hat in der letzten Stunde zwischen 11 und 25 Integritätstokens auf diesem Gerät angefordert. | Die App hat in der letzten Stunde zwischen 6 und 15 Integritätstokens auf diesem Gerät angefordert. |
LEVEL_3 |
Die App hat in der letzten Stunde zwischen 26 und 50 Integritätstokens auf diesem Gerät angefordert. | Die App hat in der letzten Stunde zwischen 16 und 30 Integritätstokens auf diesem Gerät angefordert. |
LEVEL_4 (höchste) |
Die App hat in der letzten Stunde mehr als 50 Integritätstokens auf diesem Gerät angefordert. | Die App hat in der letzten Stunde mehr als 30 Integritätstokens auf diesem Gerät angefordert. |
UNEVALUATED |
Die letzten Geräteaktivitäten wurden nicht ausgewertet.
Dafür kann es verschiedene Gründe geben:
|
Feld für Kontodetails
Das Feld accountDetails
enthält den einzelnen Wert appLicensingVerdict
für den Lizenzierungsstatus der Anwendung.
accountDetails: { // This field can be LICENSED, UNLICENSED, or UNEVALUATED. appLicensingVerdict: "LICENSED" }
appLicensingVerdict
kann einen der folgenden Werte haben:
LICENSED
- Der Nutzer hat eine App-Berechtigung. Mit anderen Worten: Der Nutzer hat deine App bei Google Play installiert oder gekauft.
UNLICENSED
- Der Nutzer hat keine App-Berechtigung. Das ist beispielsweise der Fall, wenn der Nutzer deine App per Sideload oder nicht bei Google Play herunterlädt. Sie können Nutzern das Dialogfeld LIZENZ_LIZENZIEREN einblenden, um das Problem zu beheben.
UNEVALUATED
Lizenzierungsdetails wurden nicht ausgewertet, da eine erforderliche Voraussetzung nicht erfüllt wurde.
Dafür kann es verschiedene Gründe geben:
- Das Gerät ist nicht vertrauenswürdig genug.
- Die Version der auf dem Gerät installierten App ist Google Play nicht bekannt.
- Der Nutzer ist nicht in Google Play angemeldet.
Wenn du prüfen möchtest, ob der Nutzer eine App-Berechtigung für deine App hat, prüfe, ob appLicensingVerdict
wie erwartet ist, wie im folgenden Code-Snippet gezeigt:
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! }
Feld für Umgebungsdetails
Wenn Sie sich in der Google Play Console für das Ergebnis von Play Protect angemeldet haben, enthält Ihre API-Antwort das Feld environmentDetails
. Das Feld environmentDetails
enthält den einzelnen Wert playProtectVerdict
, der Informationen zu Google Play Protect auf dem Gerät liefert.
environmentDetails: { playProtectVerdict: "NO_ISSUES" }
playProtectVerdict
kann einen der folgenden Werte haben:
NO_ISSUES
- Play Protect ist aktiviert und hat auf dem Gerät keine App-Probleme gefunden.
NO_DATA
- Play Protect ist aktiviert, aber es wurde noch kein Scan durchgeführt. Das Gerät oder die Play Store App wurde möglicherweise vor Kurzem zurückgesetzt.
POSSIBLE_RISK
- Play Protect ist deaktiviert.
MEDIUM_RISK
- Play Protect ist aktiviert und hat potenziell schädliche Apps gefunden, die auf dem Gerät installiert sind.
HIGH_RISK
- Play Protect ist aktiviert und hat gefährliche Apps gefunden, die auf dem Gerät installiert sind.
UNEVALUATED
Das Ergebnis von Play Protect wurde nicht bewertet.
Dafür kann es verschiedene Gründe geben:
- Das Gerät ist nicht vertrauenswürdig genug.
- Nur Spiele: Das Nutzerkonto ist nicht
LICENSED
.
So verwendest du das Play Protect-Ergebnis
Der Back-End-Server Ihrer App kann auf Grundlage des Ergebnisses anhand Ihrer Risikotoleranz entscheiden, wie zu verfahren ist. Hier sind einige Vorschläge und mögliche Nutzeraktionen:
NO_ISSUES
- Play Protect ist aktiviert und hat keine Probleme festgestellt, daher sind keine Nutzeraktionen erforderlich.
POSSIBLE_RISK
undNO_DATA
- Wenn der Nutzer diese Ergebnisse erhält, muss er prüfen, ob Play Protect aktiviert ist und einen Scan durchgeführt hat.
NO_DATA
sollte nur in seltenen Fällen angezeigt werden. MEDIUM_RISK
undHIGH_RISK
- Je nach Risikotoleranz kannst du den Nutzer bitten, Play Protect zu starten und auf die Play Protect-Warnungen zu reagieren. Wenn der Nutzer diese Anforderungen nicht erfüllen kann, können Sie ihn für die Serveraktion blockieren.