Auf dieser Seite wird beschrieben, wie Sie Standard-API-Anfragen für Integritätsprüfungen stellen, die unter Android 5.0 (API-Level 21) oder höher unterstützt werden. Sie können eine Standard-API-Anfrage für ein Integritätsurteil stellen, wenn Ihre App einen Serveraufruf ausführt, um zu prüfen, ob die Interaktion echt ist.
Übersicht
Eine Standardanfrage besteht aus zwei Teilen:
- Integritätstokenanbieter vorbereiten (einmalig): Sie müssen die Integrity API aufrufen, um den Integritätstokenanbieter vorzubereiten, bevor Sie das Integritätsergebnis abrufen müssen. Sie können dies beispielsweise beim Starten Ihrer App oder im Hintergrund tun, bevor das Integritätsurteil benötigt wird.
- Bei Bedarf ein Integritätstoken anfordern: Immer wenn Ihre App eine Serveranfrage stellt, die Sie auf ihre Echtheit prüfen möchten, fordern Sie ein Integritätstoken an und senden es zur Entschlüsselung und Überprüfung an den Backend-Server Ihrer App. Ihr Backend-Server kann dann entscheiden, wie er als Nächstes vorgehen soll.
Integritätstoken-Anbieter vorbereiten (einmalig):
- Ihre App ruft den Integritätstokenanbieter mit Ihrer Google Cloud-Projektnummer auf.
- Ihre App speichert den Anbieter des Integritätstokens im Arbeitsspeicher für weitere Attestierungsprüfungen.
Integritätstoken anfordern (bei Bedarf):
- Für die zu schützende Nutzeraktion berechnet Ihre App den Hash der zu stellenden Anfrage mit einem geeigneten Hash-Algorithmus wie SHA256.
- Ihre App fordert ein Integritätstoken an und übergibt den Anfrage-Hash.
- Ihre App erhält das signierte und verschlüsselte Integritätstoken von der Play Integrity API.
- Ihre App übergibt das Integritätstoken an das Backend Ihrer App.
- Das Backend Ihrer App sendet das Token an einen Google Play-Server. Der Google Play-Server entschlüsselt und überprüft das Ergebnis und gibt die Ergebnisse an das Backend Ihrer App zurück.
- Das Backend Ihrer App entscheidet anhand der Signale in der Token-Payload, wie es weitergeht.
- Das Backend Ihrer App sendet die Entscheidungsergebnisse an Ihre App.
Integritätstoken-Anbieter vorbereiten (einmalig)
Bevor Sie eine Standardanfrage für ein Integritätsurteil von Google Play stellen, müssen Sie den Integritätstokenanbieter vorbereiten („aufwärmen“). Dadurch kann Google Play teilweise Attestinformationen auf dem Gerät intelligent im Cache speichern, um die Latenz auf dem kritischen Pfad zu verringern, wenn Sie ein Integritätsurteil anfordern. Wenn Sie den Tokenanbieter noch einmal vorbereiten, können Sie weniger ressourcenintensive Integritätsprüfungen wiederholen, damit das nächste von Ihnen angeforderte Integritätsurteil aktueller ist.
Sie können den Integritätstokenanbieter vorbereiten:
- Beim Starten Ihrer App (d.h. beim Kaltstart). Die Vorbereitung des Tokenanbieters erfolgt asynchron und wirkt sich daher nicht auf die Startzeit aus. Diese Option eignet sich gut, wenn Sie kurz nach dem Start der App eine Anfrage für ein Integritätsergebnis stellen möchten, z. B. wenn sich ein Nutzer anmeldet oder ein Spieler einem Spiel beitritt.
- Wenn Ihre App geöffnet wird (z.B. bei einem Warmstart). Jede App-Instanz kann das Integritätstoken jedoch nur bis zu fünf Mal pro Minute vorbereiten.
- Jederzeit im Hintergrund, wenn Sie das Token im Voraus für eine Anfrage zum Integritätsurteil vorbereiten möchten.
So bereiten Sie den Anbieter von Integritätstokens vor:
- Erstellen Sie ein
StandardIntegrityManager
, wie in den folgenden Beispielen gezeigt. - Erstellen Sie ein
PrepareIntegrityTokenRequest
und geben Sie die Google Cloud-Projektnummer über die MethodesetCloudProjectNumber()
an. - Rufen Sie
prepareIntegrityToken()
mit dem Manager auf und geben Sie diePrepareIntegrityTokenRequest
an.
Java
import com.google.android.gms.tasks.Task; // Create an instance of a manager. StandardIntegrityManager standardIntegrityManager = IntegrityManagerFactory.createStandard(applicationContext); StandardIntegrityTokenProvider integrityTokenProvider; long cloudProjectNumber = ...; // Prepare integrity token. Can be called once in a while to keep internal // state fresh. standardIntegrityManager.prepareIntegrityToken( PrepareIntegrityTokenRequest.builder() .setCloudProjectNumber(cloudProjectNumber) .build()) .addOnSuccessListener(tokenProvider -> { integrityTokenProvider = tokenProvider; }) .addOnFailureListener(exception -> handleError(exception));
Unity
IEnumerator PrepareIntegrityTokenCoroutine() { long cloudProjectNumber = ...; // Create an instance of a standard integrity manager. var standardIntegrityManager = new StandardIntegrityManager(); // Request the token provider. var integrityTokenProviderOperation = standardIntegrityManager.PrepareIntegrityToken( new PrepareIntegrityTokenRequest(cloudProjectNumber)); // Wait for PlayAsyncOperation to complete. yield return integrityTokenProviderOperation; // Check the resulting error code. if (integrityTokenProviderOperation.Error != StandardIntegrityErrorCode.NoError) { AppendStatusLog("StandardIntegrityAsyncOperation failed with error: " + integrityTokenProviderOperation.Error); yield break; } // Get the response. var integrityTokenProvider = integrityTokenProviderOperation.GetResult(); }
Unreal Engine
// .h void MyClass::OnPrepareIntegrityTokenCompleted( EStandardIntegrityErrorCode ErrorCode, UStandardIntegrityTokenProvider* Provider) { // Check the resulting error code. if (ErrorCode == EStandardIntegrityErrorCode::StandardIntegrity_NO_ERROR) { // ... } } // .cpp void MyClass::PrepareIntegrityToken() { int64 CloudProjectNumber = ... // Create the Integrity Token Request. FPrepareIntegrityTokenRequest Request = { CloudProjectNumber }; // Create a delegate to bind the callback function. FPrepareIntegrityOperationCompletedDelegate Delegate; // Bind the completion handler (OnPrepareIntegrityTokenCompleted) to the delegate. Delegate.BindDynamic(this, &MyClass::OnPrepareIntegrityTokenCompleted); // Initiate the prepare integrity token operation, passing the delegate to handle the result. GetGameInstance() ->GetSubsystem<UStandardIntegrityManager>() ->PrepareIntegrityToken(Request, Delegate); }
Nativ
/// Initialize StandardIntegrityManager StandardIntegrityManager_init(/* app's java vm */, /* an android context */); /// Create a PrepareIntegrityTokenRequest opaque object. int64_t cloudProjectNumber = ...; PrepareIntegrityTokenRequest* tokenProviderRequest; PrepareIntegrityTokenRequest_create(&tokenProviderRequest); PrepareIntegrityTokenRequest_setCloudProjectNumber(tokenProviderRequest, cloudProjectNumber); /// Prepare a StandardIntegrityTokenProvider opaque type pointer and call /// StandardIntegrityManager_prepareIntegrityToken(). StandardIntegrityTokenProvider* tokenProvider; StandardIntegrityErrorCode error_code = StandardIntegrityManager_prepareIntegrityToken(tokenProviderRequest, &tokenProvider); /// ... /// Proceed to polling iff error_code == STANDARD_INTEGRITY_NO_ERROR if (error_code != STANDARD_INTEGRITY_NO_ERROR) { /// Remember to call the *_destroy() functions. return; } /// ... /// Use polling to wait for the async operation to complete. IntegrityResponseStatus token_provider_status; /// Check for error codes. StandardIntegrityErrorCode error_code = StandardIntegrityTokenProvider_getStatus(tokenProvider, &token_provider_status); if (error_code == STANDARD_INTEGRITY_NO_ERROR && token_provider_status == INTEGRITY_RESPONSE_COMPLETED) { /// continue to request token from the token provider } /// ... /// Remember to free up resources. PrepareIntegrityTokenRequest_destroy(tokenProviderRequest);
Anfragen vor Manipulationen schützen (empfohlen)
Wenn Sie eine Nutzeraktion in Ihrer App mit der Play Integrity API prüfen, können Sie das Feld requestHash
verwenden, um Manipulationen zu verhindern. Beispielsweise möchte ein Spiel die Punktzahl des Spielers an den Backend-Server des Spiels senden. Ihr Server möchte sicherstellen, dass diese Punktzahl nicht von einem Proxyserver manipuliert wurde. Die Play Integrity API gibt den Wert zurück, den Sie im Feld requestHash
in der signierten Integritätsantwort festgelegt haben. Ohne die requestHash
ist das Integritätstoken nur an das Gerät gebunden, nicht aber an die jeweilige Anfrage, was die Möglichkeit eines Angriffs eröffnet. In der folgenden Anleitung wird beschrieben, wie Sie das Feld requestHash
effektiv nutzen können:
Wenn Sie ein Integritätsergebnis anfordern, gilt Folgendes:
- Berechnen Sie einen Digest aller relevanten Anfrageparameter (z.B. SHA256 einer stabilen Anfrage-Serialisierung) aus der Nutzeraktion oder Serveranfrage, die gerade stattfindet. Der im Feld
requestHash
festgelegte Wert darf maximal 500 Byte lang sein. Fügen Sie alle App-Anfragedaten inrequestHash
ein, die für die Aktion, die Sie prüfen oder schützen, von entscheidender Bedeutung oder relevant sind. Das FeldrequestHash
ist unverändert im Integritätstoken enthalten. Lange Werte können daher die Anfragengröße erhöhen. - Stellen Sie den Digest als
requestHash
-Feld für die Play Integrity API bereit und rufen Sie das Integritätstoken ab.
Wenn Sie ein Integritätsergebnis erhalten:
- Decodieren Sie das Integritätstoken und extrahieren Sie das Feld
requestHash
. - Berechnen Sie einen Digest der Anfrage auf dieselbe Weise wie in der App (z.B. SHA256 einer stabilen Anfrage-Serialisierung).
- Vergleichen Sie die App- und Serverseiten-Zusammenfassungen. Wenn sie nicht übereinstimmen, ist die Anfrage nicht vertrauenswürdig.
Integritätsergebnis anfordern (auf Anfrage)
Nachdem Sie den Anbieter für das Integritätstoken vorbereitet haben, können Sie Integritätsergebnisse von Google Play anfordern. Führen Sie dazu folgende Schritte aus:
StandardIntegrityTokenProvider
erhalten.- Erstellen Sie eine
StandardIntegrityTokenRequest
und geben Sie den Anfrage-Hash der Nutzeraktion an, die Sie mit der MethodesetRequestHash
schützen möchten. - Rufen Sie
request()
mit dem Anbieter für Integritätstokens auf und geben Sie dieStandardIntegrityTokenRequest
an.
Java
import com.google.android.gms.tasks.Task; StandardIntegrityTokenProvider integrityTokenProvider; // See above how to prepare integrityTokenProvider. // Request integrity token by providing a user action request hash. Can be called // several times for different user actions. String requestHash = "2cp24z..."; Task<StandardIntegrityToken> integrityTokenResponse = integrityTokenProvider.request( StandardIntegrityTokenRequest.builder() .setRequestHash(requestHash) .build()); integrityTokenResponse .addOnSuccessListener(response -> sendToServer(response.token())) .addOnFailureListener(exception -> handleError(exception));
Unity
IEnumerator RequestIntegrityTokenCoroutine() { StandardIntegrityTokenProvider integrityTokenProvider; // See above how to prepare integrityTokenProvider. // Request integrity token by providing a user action request hash. Can be called // several times for different user actions. String requestHash = "2cp24z..."; var integrityTokenOperation = integrityTokenProvider.Request( new StandardIntegrityTokenRequest(requestHash) ); // Wait for PlayAsyncOperation to complete. yield return integrityTokenOperation; // Check the resulting error code. if (integrityTokenOperation.Error != StandardIntegrityErrorCode.NoError) { AppendStatusLog("StandardIntegrityAsyncOperation failed with error: " + integrityTokenOperation.Error); yield break; } // Get the response. var integrityToken = integrityTokenOperation.GetResult(); }
Unreal Engine
// .h void MyClass::OnRequestIntegrityTokenCompleted( EStandardIntegrityErrorCode ErrorCode, UStandardIntegrityToken* Response) { // Check the resulting error code. if (ErrorCode == EStandardIntegrityErrorCode::StandardIntegrity_NO_ERROR) { // Get the token. FString Token = Response->Token; } } // .cpp void MyClass::RequestIntegrityToken() { UStandardIntegrityTokenProvider* Provider = ... // Prepare the UStandardIntegrityTokenProvider. // Request integrity token by providing a user action request hash. Can be called // several times for different user actions. FString RequestHash = ...; FStandardIntegrityTokenRequest Request = { RequestHash }; // Create a delegate to bind the callback function. FStandardIntegrityOperationCompletedDelegate Delegate; // Bind the completion handler (OnRequestIntegrityTokenCompleted) to the delegate. Delegate.BindDynamic(this, &MyClass::OnRequestIntegrityTokenCompleted); // Initiate the standard integrity token request, passing the delegate to handle the result. Provider->Request(Request, Delegate); }
Nativ
/// Create a StandardIntegrityTokenRequest opaque object. const char* requestHash = ...; StandardIntegrityTokenRequest* tokenRequest; StandardIntegrityTokenRequest_create(&tokenRequest); StandardIntegrityTokenRequest_setRequestHash(tokenRequest, requestHash); /// Prepare a StandardIntegrityToken opaque type pointer and call /// StandardIntegrityTokenProvider_request(). Can be called several times for /// different user actions. See above how to prepare token provider. StandardIntegrityToken* token; StandardIntegrityErrorCode error_code = StandardIntegrityTokenProvider_request(tokenProvider, tokenRequest, &token); /// ... /// Proceed to polling iff error_code == STANDARD_INTEGRITY_NO_ERROR if (error_code != STANDARD_INTEGRITY_NO_ERROR) { /// Remember to call the *_destroy() functions. return; } /// ... /// Use polling to wait for the async operation to complete. IntegrityResponseStatus token_status; /// Check for error codes. StandardIntegrityErrorCode error_code = StandardIntegrityToken_getStatus(token, &token_status); if (error_code == STANDARD_INTEGRITY_NO_ERROR && token_status == INTEGRITY_RESPONSE_COMPLETED) { const char* integrityToken = StandardIntegrityToken_getToken(token); } /// ... /// Remember to free up resources. StandardIntegrityTokenRequest_destroy(tokenRequest); StandardIntegrityToken_destroy(token); StandardIntegrityTokenProvider_destroy(tokenProvider); StandardIntegrityManager_destroy();
Wenn Ihre App den gleichen Tokenanbieter zu lange verwendet, kann der Tokenanbieter ablaufen, was bei der nächsten Tokenanfrage zum Fehler INTEGRITY_TOKEN_PROVIDER_INVALID führt. Sie sollten diesen Fehler beheben, indem Sie einen neuen Anbieter anfordern.
Integritätsergebnis entschlüsseln und prüfen
Nachdem Sie ein Integritätsergebnis angefordert haben, stellt die Play Integrity API ein verschlüsseltes Antworttoken bereit. Um die Ergebnisse zur Geräteintegrität zu erhalten, müssen Sie das Integritätstoken auf den Google-Servern entschlüsseln. Führen Sie dazu die folgenden Schritte aus:
- Erstellen Sie ein Dienstkonto im Google Cloud-Projekt, das mit Ihrer App verknüpft ist.
Rufen Sie auf dem Server Ihrer App das Zugriffstoken mit dem Bereich „playintegrity“ aus den Anmeldedaten Ihres Dienstkontos ab und senden Sie die folgende Anfrage:
playintegrity.googleapis.com/v1/PACKAGE_NAME:decodeIntegrityToken -d \ '{ "integrity_token": "INTEGRITY_TOKEN" }'
Lesen Sie die JSON-Antwort.
Die resultierende Nutzlast ist ein Nur-Text-Token, das Integritätsurteile enthält.
Automatischer Schutz vor Replay-Angriffen
Um Wiederholungsversuche zu verhindern, verhindert Google Play automatisch, dass Integritätstokens mehrmals wiederverwendet werden. Wenn Sie versuchen, dasselbe Token wiederholt zu entschlüsseln, werden die folgenden Ergebnisse zurückgegeben:
- Das Ergebnis der Geräteerkennung ist leer.
- Das Ergebnis zur App-Erkennung und das Ergebnis zur App-Lizenzierung werden auf
UNEVALUATED
gesetzt. - Alle optionalen Ergebnisse, die über die Play Console aktiviert werden, werden auf
UNEVALUATED
festgelegt (oder auf ein leeres Ergebnis, wenn es sich um ein Ergebnis mit mehreren Werten handelt).