In questa pagina vengono descritte richieste API standard per esiti relativi all'integrità, supportate su Android 5.0 (livello API 21) o versioni successive. Puoi effettuare una richiesta API standard per ottenere un esito relativo all'integrità ogni volta che l'app effettua una chiamata al server per verificare se l'interazione è autentica.
Panoramica
Una richiesta standard è costituita da due parti:
- Prepara il provider del token di integrità (una tantum): devi chiamare l'API Integrity per preparare con largo anticipo il provider del token di integrità prima di ottenere l'esito relativo all'integrità. Ad esempio, puoi farlo quando l'app viene avviata o in background prima che sia necessario l'esito relativo all'integrità.
- Richiedi un token di integrità (on demand): ogni volta che la tua app invia una richiesta del server che vuoi verificare che sia autentica, devi richiedere un token di integrità e inviarlo al server di backend dell'app per la decrittografia e la verifica. Quindi, il tuo server di backend può decidere come agire.
Prepara il provider del token di integrità (una tantum):
- L'app chiama il provider di token di integrità con il numero di progetto Google Cloud.
- La tua app contiene il provider del token di integrità in memoria per ulteriori chiamate di controllo di attestazione.
Richiedi un token di integrità (on demand):
- Per l'azione utente che deve essere protetta, l'app calcola l'hash (utilizzando qualsiasi algoritmo hash adatto, come SHA256) della richiesta da effettuare.
- La tua app richiede un token di integrità, passando l'hash della richiesta.
- La tua app riceve il token di integrità firmato e criptato dall'API Play Integrity.
- La tua app passa il token di integrità al backend dell'app.
- Il backend dell'app invia il token a un server di Google Play. Il server di Google Play decripta e verifica l'esito, restituendo i risultati al backend della tua app.
- Il backend dell'app decide come procedere in base agli indicatori contenuti nel payload del token.
- Il backend dell'app invia i risultati decisionali all'app.
Prepara il provider del token di integrità (una tantum)
Prima di effettuare una richiesta standard di un esito relativo all'integrità da parte di Google Play, devi preparare (o "preparare") il provider del token di integrità. Ciò consente a Google Play di memorizzare in modo intelligente nella cache le informazioni di attestazione parziali sul dispositivo al fine di ridurre la latenza sul percorso critico quando richiedi un esito sull'integrità. La preparazione del provider di token di nuovo consente di ripetere meno controlli di integrità delle risorse, il che renderà più aggiornato l'esito relativo all'integrità da te richiesto.
Puoi preparare il provider del token di integrità:
- Quando si avvia l'app (ad esempio all'avvio a freddo). La preparazione del provider di token è asincrona e, di conseguenza, non influisce sui tempi di avvio. Questa opzione è adatta se hai intenzione di effettuare una richiesta di esito relativo all'integrità poco dopo il lancio dell'app, ad esempio quando un utente accede o un giocatore partecipa a un gioco.
- Quando l'app è aperta (ad esempio all'avvio tiepido). Tuttavia, tieni presente che ogni istanza di app può preparare il token di integrità solo fino a cinque volte al minuto.
- In qualsiasi momento in background, quando vuoi preparare il token prima di una richiesta di esito relativo all'integrità.
Per preparare il provider di token di integrità:
- Crea un
StandardIntegrityManager
, come mostrato negli esempi seguenti. - Crea un
PrepareIntegrityTokenRequest
, fornendo il numero di progetto Google Cloud tramite il metodosetCloudProjectNumber()
. - Utilizza il gestore per chiamare
prepareIntegrityToken()
, fornendo ilPrepareIntegrityTokenRequest
.
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(); }
Nativo
/// 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);
Proteggi le richieste dalle manomissioni (opzione consigliata)
Quando controlli un'azione utente nella tua app con l'API Play Integrity, puoi usare il campo requestHash
per mitigare gli attacchi di manomissione. Ad esempio, per un gioco potrebbe essere necessario segnalare il punteggio del giocatore al server di backend del gioco e il server vuole assicurarsi che il punteggio non sia stato manomesso da un server proxy. L'API Play Integrity restituisce il valore che hai impostato nel
campo requestHash
all'interno della risposta di integrità firmata. Senza requestHash
, il token di integrità sarà associato solo al dispositivo, ma non alla richiesta specifica, il che apre la possibilità di un attacco. Le seguenti istruzioni descrivono come utilizzare in modo efficace il campo requestHash
:
Quando richiedi un esito relativo all'integrità:
- Calcola un digest di tutti i parametri di richiesta pertinenti (ad es. SHA256 di una serializzazione di richiesta stabile) dall'azione utente o dalla richiesta del server in corso. Il valore impostato nel campo
requestHash
ha una lunghezza massima di 500 byte. Includi nelrequestHash
i dati delle richieste dell'app che sono fondamentali o pertinenti per l'azione che stai controllando o proteggendo. Il camporequestHash
è incluso testualmente nel token di integrità, pertanto i valori a lungo termine potrebbero aumentare le dimensioni della richiesta. - Fornisci il digest come campo
requestHash
all'API Play Integrity e recupera il token di integrità.
Quando ricevi un esito relativo all'integrità:
- Decodifica il token di integrità ed estrai il campo
requestHash
. - Calcola un digest della richiesta come nell'app (ad es. l'algoritmo SHA256 di una serializzazione di richiesta stabile).
- Confronta i digest lato app e lato server. Se non corrispondono, la richiesta non è affidabile.
Richiedi un esito relativo all'integrità (on demand)
Dopo aver preparato il provider del token di integrità, puoi iniziare a richiedere a Google Play gli esiti sull'integrità. Per farlo, segui questi passaggi:
- Ottieni un
StandardIntegrityTokenProvider
, come mostrato sopra. - Crea un
StandardIntegrityTokenRequest
, fornendo l'hash della richiesta dell'azione utente da proteggere tramite il metodosetRequestHash
. - Utilizza il provider del token di integrità per chiamare
request()
, fornendo ilStandardIntegrityTokenRequest
.
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(); }
Nativo
/// 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();
Decripta e verifica l'esito relativo all'integrità
Dopo aver richiesto un esito relativo all'integrità, l'API Play Integrity fornisce un token di risposta criptato. Per ottenere gli esiti relativi all'integrità del dispositivo, devi decriptare il token di integrità sui server di Google. Per farlo, segui questi passaggi:
- Crea un account di servizio all'interno del progetto Google Cloud collegato alla tua app. Durante il processo di creazione dell'account, devi concedere al tuo account di servizio i ruoli Utente account di servizio e Consumatore utilizzo servizi.
Sul server dell'app, recupera il token di accesso dalle credenziali del tuo account di servizio utilizzando l'ambito di integrità ed effettua la seguente richiesta:
playintegrity.googleapis.com/v1/PACKAGE_NAME:decodeIntegrityToken -d \ '{ "integrity_token": "INTEGRITY_TOKEN" }'
Leggi la risposta JSON.
Il payload risultante è un token in testo normale che contiene verifica dell'integrità.
Protezione automatica dalle riproduzioni
Per mitigare gli attacchi di ripetizione, Google Play garantisce automaticamente che ogni token di integrità non possa essere riutilizzato molte volte. Tentativi di decriptare ripetutamente lo stesso token produrranno esiti vuoti.