Bu sayfada, Android 5.0 (API düzeyi 21) veya sonraki sürümlerde desteklenen bütünlük değerlendirmeleri için standart API istekleri oluşturma açıklanmaktadır. Uygulamanız, etkileşimin gerçek olup olmadığını kontrol etmek için sunucu çağrısı yaptığında bütünlük kararı için standart bir API isteğinde bulunabilirsiniz.
Genel Bakış
Standart istekler iki bölümden oluşur:
- Bütünlük jetonu sağlayıcıyı hazırlama (bir defaya mahsus): Bütünlük değerlendirmesini almanız gerekmeden çok önce bütünlük jetonu sağlayıcıyı hazırlamak için Integrity API'yi çağırmanız gerekir. Örneğin, uygulamanız başlatıldığında veya bütünlük değerlendirmesine ihtiyaç duyulmadan önce arka planda bu işlemi yapabilirsiniz.
- Bütünlük jetonu isteme (talep üzerine): Uygulamanız, gerçekliğini kontrol etmek istediğiniz bir sunucu isteğinde bulunduğunda bütünlük jetonu isteyip şifre çözme ve doğrulama için uygulamanızın arka uç sunucusuna gönderir. Ardından arka uç sunucunuz nasıl davranılacağını belirleyebilir.
Bütünlük jetonu sağlayıcıyı hazırlama (bir defaya mahsus):
- Uygulamanız, Google Cloud proje numaranızla bütünlük jetonu sağlayıcıyı çağırır.
- Uygulamanız, daha fazla onay kontrolü çağrısı için bütünlük jetonu sağlayıcıyı bellekte tutar.
Bütünlük jetonu isteyin (talep üzerine):
- Uygulamanız, korunması gereken kullanıcı işlemi için yapılacak isteğin karma değerini (SHA256 gibi uygun bir karma algoritması kullanarak) hesaplar.
- Uygulamanız, istek karmasını ileterek 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, değerlendirmenin şifresini çözüp doğrular ve sonuçları uygulamanızın arka ucuna döndürür.
- Uygulamanızın arka ucu, jeton yükünde yer alan sinyallere göre nasıl devam edeceğini belirler.
- Uygulamanızın arka ucu, karar sonuçlarını uygulamanıza gönderir.
Bütünlük jetonu sağlayıcıyı hazırlama (bir defaya mahsus)
Google Play'den bütünlük değerlendirmesi için standart bir istekte bulunmadan önce bütünlük jetonu sağlayıcıyı hazırlamanız ("ısıtmanız") gerekir. Bu sayede Google Play, bütünlük kararı isteğinde bulunduğunuzda kritik yoldaki gecikmeyi azaltmak için cihazda kısmi onay bilgilerini akıllıca önbelleğe alabilir. Jeton sağlayıcıyı tekrar hazırlamak, daha az kaynak yoğun bütünlük kontrollerini tekrarlamanın bir yoludur. Bu sayede, isteyeceğiniz bir sonraki bütünlük değerlendirmesi daha güncel olur.
Bütünlük jetonu sağlayıcıyı şu şekilde hazırlayabilirsiniz:
- Uygulamanız başlatıldığında (ör. baştan başlatma). Jeton sağlayıcıyı hazırlama işlemi eşzamansızdır ve bu nedenle başlatma süresini etkilemez. Bu seçenek, uygulama başlatıldıktan kısa süre sonra bütünlük kararı isteğinde bulunmayı planlıyorsanız (ör. kullanıcı oturum açtığında veya oyuncu bir oyuna katıldığında) iyi bir seçenektir.
- Uygulamanız açıldığında (ör. hazır durumda başlatma). Ancak her uygulama örneğinin dakikada en fazla 5 kez bütünlük jetonu 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 proje numarasını
setCloudProjectNumber()
yöntemiyle sağlayarak birPrepareIntegrityTokenRequest
oluşturun. prepareIntegrityToken()
adlı işlevi çağırmak için yöneticiyi kullanın vePrepareIntegrityTokenRequest
değerini sağlayın.
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); }
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 kurcalamaya karşı koruma (önerilir)
Play Integrity API ile uygulamanızdaki bir kullanıcı işlemini kontrol ederken kurcalama 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 puanın bir proxy sunucusu tarafından değiştirilmediğinden emin olmak isteyebilir. Play Integrity API, imzalı 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 ancak 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:
- Kullanıcı işleminden veya gerçekleşen sunucu isteğinden tüm alakalı istek parametrelerinin (ör. sabit bir istek serileştirmesinin SHA256'sı) özetini hesaplayın.
requestHash
alanında ayarlanan değerin maksimum uzunluğu 500 bayttır.requestHash
içinde, kontrol ettiğiniz veya koruduğunuz işlem için çok önemli ya da alakalı olan tüm uygulama isteği verilerini ekleyin.requestHash
alanı, bütünlük jetonuna kelimesi kelimesine dahil edildiğinden uzun değerler istek boyutunu artırabilir. - Özeti 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ı çıkarı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şmemeleri durumunda istek güvenilir değildir.
Bütünlük değerlendirmesi isteme (talep üzerine)
Bütünlük jetonu sağlayıcıyı hazırladıktan sonra Google Play'den bütünlük değerlendirmesi istemeye başlayabilirsiniz. Bunun için aşağıdaki adımları uygulayın:
StandardIntegrityTokenProvider
edinmeStandardIntegrityTokenRequest
oluşturun vesetRequestHash
yöntemiyle korumak istediğiniz kullanıcı işleminin istek karmasını sağlayın.request()
çağrısı yapmak için bütünlük jetonu sağlayıcıyı kullanın veStandardIntegrityTokenRequest
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(); }
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); }
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();
Uygulamanız aynı jeton sağlayıcıyı çok uzun süre kullanırsa jeton sağlayıcının süresi dolabilir. Bu durumda, sonraki jeton isteğinde INTEGRITY_TOKEN_PROVIDER_INVALID hatası oluşur. Yeni bir sağlayıcı isteyerek bu hatayı gidermeniz gerekir.
Bütünlük değerlendirmesini şifre çö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 hizmet hesabı oluşturun.
Uygulamanızın sunucusunda, playintegrity kapsamını kullanarak hizmet hesabı kimlik bilgilerinizden erişim jetonunu getirin ve şu 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 biçiminde bir jetondur.
Otomatik yeniden oynatma koruması
Google Play, tekrar oynatma saldırılarını azaltmak için bütünlük jetonlarının birçok kez yeniden kullanılmasını otomatik olarak engeller. Aynı jetonun tekrar tekrar şifresini çözmeye çalışmak, aşağıdaki gibi temizlenmiş kararlara neden olur:
- 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ın tümü
UNEVALUATED
olarak ayarlanır (veya çok değerli bir karar ise boş bir karar olarak ayarlanır).
Google Play istemiyle karar sorunlarını düzeltme (isteğe bağlı)
Sunucunuz bir bütünlük kararı aldıktan sonra nasıl devam edeceğine karar verebilir. Kararda, uygulamanın lisanssız olması, değiştirilmesi veya cihazın güvenliğinin ihlal edilmesi gibi bir sorun olduğu belirtiliyorsa kullanıcılara sorunu kendilerinin düzeltmesi için şans verebilirsiniz.
Play Integrity API, kullanıcıdan işlem yapmasını (ör. uygulamanızın resmi sürümünü Google Play'den edinmesini) isteyen bir Google Play iletişim kutusu gösterme seçeneği sunar.
Bu iletişim kutularını sunucunun yanıtına göre uygulamanızdan nasıl tetikleyeceğinizi öğrenmek için Düzeltme iletişim kutuları bölümüne bakın.
Cihaz bütünlüğüyle ilgili bir sorunu gidermede yardıma ihtiyaç duyarlarsa kullanıcılarınızı bu destek sayfasına yönlendirebilirsiniz.