Bu sayfada, Android 5.0 (API düzeyi 21) veya sonraki sürümlerde desteklenen bütünlük kararları için standart API isteklerinin nasıl oluşturulacağı açıklanmaktadır. Uygulamanız bir sunucu çağrısı yaptığında etkileşimin gerçek olup olmadığını kontrol etmek için bütünlük kararı için standart bir API isteği gönderebilirsiniz.
Genel Bakış
Standart istek iki bölümden oluşur:
- Bütünlük jetonu sağlayıcıyı hazırlama (tek seferlik): Bütünlük jetonu sağlayıcıyı hazırlamak için Integrity API'yi çağırmanız gerekir. Bu işlem, bütünlük değerlendirmesi size ulaşmadan uzun süre önce yapılmalıdır. Örneğin, bunu uygulamanız başlatılırken veya bütünlük değerlendirmesi gerekmeden önce arka planda yapabilirsiniz.
- Bütünlük jetonu isteme (isteme üzerine): Uygulamanız, orijinal olup olmadığını kontrol etmek istediğiniz bir sunucu isteği gönderdiğinde bütünlük jetonu ister ve şifre çözme ve doğrulama için uygulamanızın arka uç sunucusuna gönderirsiniz. Ardından arka uç sunucunuz nasıl hareket edeceğine karar verebilir.
Bütünlük jetonu sağlayıcıyı hazırlama (tek seferlik):
- Uygulamanız, Google Cloud proje numaranızla bütünlük jetonu sağlayıcıyı çağırır.
- Uygulamanız, daha fazla doğrulama kontrolü çağrısı için bütünlük jetonu sağlayıcısını bellekte tutar.
Bütünlük jetonu isteme (istediğiniz zaman):
- Uygulamanız, korunması gereken kullanıcı işlemi için yapılacak isteğin karma değerini (SHA256 gibi uygun bir karma oluşturma algoritması kullanarak) hesaplar.
- Uygulamanız, istek karmasını ileterek bir bütünlük jetonu ister.
- Uygulamanız, Play Integrity API'den imzalı ve şifrelenmiş bütünlük jetonunu alır.
- Uygulamanız, bütünlük jetonunu uygulamanızın arka ucuna iletir.
- Uygulamanızın arka ucu, jetonu bir Google Play sunucusuna gönderir. Google Play sunucusu, sonucun şifresini çözer ve doğrular, ardından sonuçları uygulamanızın arka ucuna döndürür.
- Uygulamanızın arka ucu, jeton yükünde bulunan sinyallere göre nasıl devam edileceğine karar verir.
- Uygulamanızın arka ucu, karar sonuçlarını uygulamanıza gönderir.
Bütünlük jetonu sağlayıcıyı hazırlama (tek seferlik)
Google Play'den standart bir bütünlük değerlendirmesi isteği göndermeden önce bütünlük jetonu sağlayıcıyı hazırlamanız (veya "ısıtmanız") gerekir. Bu sayede Google Play, bütünlük kararı isteği gönderdiğinizde kritik yoldaki gecikmeyi azaltmak için cihazda kısmi doğrulama bilgilerini akıllıca önbelleğe alabilir. Jeton sağlayıcıyı tekrar hazırlamak, daha az kaynak kullanan bütünlük kontrollerini tekrar etmenin bir yoludur. Bu, istediğiniz bir sonraki bütünlük kararını daha güncel hale getirir.
Bütünlük jetonu sağlayıcıyı hazırlayabilirsiniz:
- Uygulamanız başlatıldığında (ör. baştan başlatma sırasında). Jeton sağlayıcının hazırlanması eşzamansız olduğundan başlangıç süresini etkilemez. Bu seçenek, uygulama kullanıma sunulduktan kısa bir süre sonra (ör. bir kullanıcı oturum açtığında veya bir oyuncu oyuna katıldığında) bütünlük kararı isteği göndermeyi planlıyorsanız uygundur.
- Uygulamanız açıldığında (ör. hazır durumda başlatma). Ancak her uygulama örneğinin, bütünlük jetonunu dakikada en fazla 5 kez hazırlayabileceğini unutmayın.
- Arka planda dilediğiniz zaman bütünlük değerlendirmesi isteğinden önce jetonu hazırlamak istediğinizde.
Bütünlük jetonu sağlayıcıyı hazırlamak için aşağıdakileri yapın:
- Aşağıdaki örneklerde gösterildiği gibi bir
StandardIntegrityManager
oluşturun. - Google Cloud projesi numarasını
setCloudProjectNumber()
yöntemiyle sağlayarak birPrepareIntegrityTokenRequest
oluşturun. - Yöneticiyi kullanarak
prepareIntegrityToken()
'ü arayın vePrepareIntegrityTokenRequest
'yi belirtin.
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(); }
Yerel
/// 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);
İstekleri izinsiz olarak değiştirilmeye karşı koruma (önerilir)
Uygulamanızdaki bir kullanıcı işlemini Play Integrity API ile kontrol ederken, tampering saldırılarını azaltmak için requestHash
alanından yararlanabilirsiniz. Örneğin, bir oyun oyuncunun puanını oyunun arka uç sunucusuna bildirmek isteyebilir ve sunucunuz bu puanda bir proxy sunucu tarafından oynanmadığından emin olmak ister. Play Integrity API, imzalanan bütünlük yanıtının içinde requestHash
alanında ayarladığınız değeri döndürür. requestHash
olmadan bütünlük jetonu yalnızca cihaza bağlanır, belirli isteğe bağlanmaz. Bu da saldırı olasılığını artırır. Aşağıdaki talimatlarda, requestHash
alanının nasıl etkili bir şekilde kullanılacağı açıklanmaktadır:
Bütünlük değerlendirmesi istediğinizde:
- Devam eden kullanıcı işlemi veya sunucu isteğinden tüm alakalı istek parametrelerinin özetini (ör. kararlı bir istek serileştirmesinin SHA256'sı) hesaplayın.
requestHash
alanında ayarlanan değerin maksimum uzunluğu 500 bayttır. Kontrol ettiğiniz veya koruduğunuz işlemle ilgili veya önemli olan tüm uygulama isteği verilerinirequestHash
içine ekleyin.requestHash
alanı, bütünlük jetonuna olduğu gibi dahil edildiğinden uzun değerler istek boyutunu artırabilir. - Özetlenmiş içeriği Play Integrity API'ye
requestHash
alanı olarak sağlayın ve bütünlük jetonunu alın.
Bütünlük değerlendirmesi aldığınızda:
- Bütünlük jetonunun kodunu çözün ve
requestHash
alanını ayıklayın. - İsteğin özetini uygulamadakiyle aynı şekilde hesaplayın (ör. kararlı bir istek serileştirmesinin SHA256'sı).
- Uygulama tarafı ve sunucu tarafı özetlerini karşılaştırın. Eşleşmezlerse istek güvenilir değildir.
Bütünlük değerlendirmesi isteme (isteğe bağlı)
Bütünlük jetonu sağlayıcıyı hazırladıktan sonra Google Play'den bütünlük kararı istemeye başlayabilirsiniz. Bunun için aşağıdaki adımları uygulayın:
- Yukarıda gösterildiği gibi bir
StandardIntegrityTokenProvider
alın. setRequestHash
yöntemiyle korumak istediğiniz kullanıcı işleminin istek karmasını sağlayarak birStandardIntegrityTokenRequest
oluşturun.- Bütünlük jetonu sağlayıcıyı kullanarak
request()
çağrısı yapın veStandardIntegrityTokenRequest
değerini sağlayın.
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(); }
Yerel
/// 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();
Bütünlük değerlendirmesinin şifresini çözme ve doğrulama
Bütünlük değerlendirmesi istedikten sonra Play Integrity API şifrelenmiş bir yanıt jetonu sağlar. Cihaz bütünlüğü kararlarını almak için Google'ın sunucularında bütünlük jetonunun şifresini çözmeniz gerekir. Bunun için aşağıdaki adımları uygulayın:
- Uygulamanıza bağlı Google Cloud projesinde bir hizmet hesabı oluşturun.
Uygulamanızın sunucusunda, playintegrity kapsamını kullanarak hizmet hesabı kimlik bilgilerinizden erişim jetonunu getirin ve aşağıdaki isteği gönderin:
playintegrity.googleapis.com/v1/PACKAGE_NAME:decodeIntegrityToken -d \ '{ "integrity_token": "INTEGRITY_TOKEN" }'
JSON yanıtını okuyun.
Elde edilen yük, bütünlük kararlarını içeren düz metin jetonudur.
Otomatik yeniden oynatma koruması
Google Play, yeniden oynatma saldırılarını azaltmak için her bir bütünlük jetonunun birçok kez yeniden kullanılamamasını otomatik olarak sağlar. Aynı jetonun şifresini tekrar tekrar çözmeye çalışmak, temiz sonuç alınmasına neden olur. Tekrar oynatmaya karşı korumalı jetonlar için, kodu çözülmüş kararlar aşağıdaki gibi döndürülür:
- Cihaz tanıma kararı boş olur.
- Uygulama tanıma kararı ve uygulama lisanslama kararı
UNEVALUATED
olarak ayarlanır. - Play Console kullanılarak etkinleştirilen isteğe bağlı kararlar
UNEVALUATED
olarak ayarlanır (veya çok değerli bir kararsa boş bir karar olarak ayarlanır).