Tworzenie standardowego żądania do interfejsu API

Na tej stronie opisujemy wykonywanie standardowych żądań do interfejsu API w celu oceny integralności, które są obsługiwane na Androidzie 5.0 (poziom interfejsu API 21) lub nowszym. Możesz utworzyć standardowy Żądanie do interfejsu API dotyczące oceny integralności za każdym razem, gdy aplikacja wykonuje wywołanie serwera pod kątem autentyczności interakcji.

Omówienie

Diagram sekwencji przedstawiający ogólny projekt Play Integrity.
Interfejs API

Żądanie standardowe składa się z 2 części:

  • Przygotuj dostawcę tokena integralności: musisz wywołać metodę Integrity API, aby przygotować dostawcę tokena integralności na długo, zanim zajdzie taka potrzeba aby uzyskać ocenę integralności. Możesz to zrobić na przykład wtedy, gdy Twoja aplikacja jest uruchamiana lub w tle, zanim będzie potrzebna ocena integralności.
  • Wysyłaj żądanie tokena integralności (na żądanie): za każdym razem, gdy aplikacja utworzy serwer pojawia się prośba o token integralności, i wysyłają na serwer backendu aplikacji w celu odszyfrowania i weryfikacji. Serwer backendu może wtedy podjąć odpowiednie działania.

Przygotuj dostawcę tokena integralności (jeden raz):

  1. Aplikacja wywołuje dostawcę tokena integralności za pomocą projektu Google Cloud numer.
  2. Aplikacja przechowuje dostawcę tokena integralności w pamięci na potrzeby dalszego działania i sprawdzania atestu.

Wysyłanie żądania tokena integralności (na żądanie):

  1. W przypadku działania użytkownika, które musi być chronione, aplikacja oblicza hasz. (za pomocą dowolnego odpowiedniego algorytmu szyfrowania, np. SHA256) żądania, które ma zostać wysłane.
  2. Aplikacja prosi o token integralności, przekazując hasz żądania.
  3. Twoja aplikacja otrzymuje podpisany i zaszyfrowany token integralności z Google Play. Integrity API.
  4. Aplikacja przekazuje token integralności do backendu aplikacji.
  5. Backend aplikacji wysyła token do serwera Google Play. Google Play Serwer odszyfrowuje i weryfikuje ocenę, zwracając wyniki do źródła aplikacji z backendem.
  6. Backend aplikacji decyduje, co zrobić dalej, na podstawie sygnałów ładunek tokena.
  7. Backend aplikacji wysyła do niej wyniki decyzji.

Przygotowywanie dostawcy tokena integralności (jeden wyłączony)

Zanim prześlesz do Google Play standardową prośbę o ocenę integralności, musisz przygotować (czyli „rozgrzewać”) dostawcę tokena integralności. Dzięki temu Google Graj, aby inteligentnie przechowywać w pamięci podręcznej informacje o częściowym atestach na urządzeniu w celu skrócenie czasu oczekiwania na ścieżce krytycznej przy wysyłaniu żądania dla ocenę integralności. Ponowne przygotowanie dostawcy tokena pozwala ograniczyć liczbę powtarzania testy integralności intensywnie korzystające z zasobów, co wykona kolejną ocenę integralności aby poprosić o bardziej aktualne informacje.

Możesz przygotować dostawcę tokena integralności:

  • Po uruchomieniu aplikacji (np. przy uruchomieniu „na zimno”). Przygotowuję dostawcę tokena jest asynchroniczny, więc nie będzie wpływać na czas uruchamiania. Ta opcja spowoduje działa dobrze, jeśli planujesz prośbę o ocenę spójności wkrótce po jest uruchamiana, np. gdy użytkownik się loguje lub gracz dołącza do gry.
  • Kiedy aplikacja jest uruchomiona (np. podczas uruchamiania częściowo z pamięci). Pamiętaj jednak, że każda aplikacja może przygotować token integralności maksymalnie 5 razy na minutę.
  • w dowolnym momencie w tle, gdy chcesz przygotować token z wyprzedzeniem; żądania oceny integralności.

Aby przygotować dostawcę tokena integralności, wykonaj te czynności:

  1. Utwórz StandardIntegrityManager w sposób opisany w przykładach poniżej.
  2. Zbuduj PrepareIntegrityTokenRequest udostępniający Google Cloud numeru projektu za pomocą metody setCloudProjectNumber().
  3. Użyj menedżera, aby wywołać funkcję prepareIntegrityToken() i podać PrepareIntegrityTokenRequest
.

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));

Jedność

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();
}

Rodzimy użytkownik

/// 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);

Chroń żądania przed manipulacją (zalecane)

Gdy sprawdzasz działania użytkownika w aplikacji za pomocą interfejsu Play Integrity API, może wykorzystać pole requestHash do ograniczenia ataków z powodu manipulacji. Dla: na przykład gra może chcieć zgłosić wynik gracza do backendu gry , a Twój serwer chce mieć pewność, że ten wynik nie został zmieniony przez serwer proxy. Interfejs Play Integrity API zwraca wartość ustawioną w polu requestHash w podpisanej odpowiedzi dotyczącej integralności. Bez requestHash, token integralności będzie powiązany tylko z urządzeniem, ale nie z urządzeniem konkretnego żądania, co stwarza ryzyko ataku. Poniżej instrukcje pozwalają skutecznie korzystać z pola requestHash:

Gdy poprosisz o ocenę integralności:

  • Oblicz podsumowanie wszystkich odpowiednich parametrów żądania (np. SHA256 stabilnej wersji żądania serializacji) z działania użytkownika lub żądania serwera, co się dzieje. Maksymalna długość wartości ustawionej w polu requestHash to 500 bajtów. Umieść w pliku requestHash wszystkie żądania z aplikacji, które są kluczowe lub powiązane z sprawdzanym lub chronionym działaniem. Token integralności zawiera pole requestHash w sposób dosłowny, więc ciąg znaków mogą zwiększyć rozmiar żądania.
  • przekazać skrót w postaci pola requestHash do interfejsu Play Integrity API; uzyskać token integralności.
.

Gdy otrzymasz ocenę integralności:

  • Zdekoduj token integralności i wyodrębnij pole requestHash.
  • Oblicz podsumowanie żądania w taki sam sposób jak w aplikacji (np. SHA256 stabilnego żądania serializacji).
  • Porównaj skróty po stronie aplikacji i serwera. Jeśli nie są zgodne, żądanie nie jest wiarygodne.
.

Wysyłanie prośby o ocenę integralności (na żądanie)

Po przygotowaniu dostawcy tokena integralności możesz zacząć wysyłać żądania oceny integralności pochodzące z Google Play. W tym celu wykonaj następujące czynności:

  1. Uzyskaj StandardIntegrityTokenProvider w sposób opisany powyżej.
  2. Utwórz obiekt StandardIntegrityTokenRequest, podając hasz żądania działanie użytkownika, które chcesz chronić za pomocą metody setRequestHash.
  3. Użyj dostawcy tokena integralności, aby wywołać request(), podając wartość StandardIntegrityTokenRequest

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));

Jedność

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();
}

Rodzimy użytkownik

/// 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();

Odszyfruj i zweryfikuj ocenę integralności

Gdy poprosisz o ocenę integralności, interfejs Play Integrity API wygeneruje zaszyfrowany token odpowiedzi. Aby uzyskać oceny integralności urządzenia, musisz odszyfrować token integralności na serwerach Google. W tym celu wykonaj następujące czynności:

  1. Tworzenie konta usługi w projekcie Google Cloud połączonym z Twoją aplikacją.
  2. Z serwera aplikacji pobierz token dostępu ze swojego konta usługi dane logowania w zakresie playintegrity i wyślij to żądanie:

    playintegrity.googleapis.com/v1/PACKAGE_NAME:decodeIntegrityToken -d \
    '{ "integrity_token": "INTEGRITY_TOKEN" }'
  3. Przeczytaj odpowiedź JSON.

Powstały w ten sposób ładunek to zwykły token tekstowy zawierający integralność .

Automatyczna ochrona przed ponownym odtwarzaniem

Aby ograniczyć ataki typu „powtórka”, Google Play automatycznie dba o to, aby każda tokenu integralności nie można wielokrotnie użyć. Wielokrotne próba odszyfrowania ten sam token spowoduje, że wyniki będą puste.