Oceny integralności

Na tej stronie opisujemy, jak interpretować zwrócony wynik weryfikacji integralności i jak z nim pracować. Niezależnie od tego, czy wyślesz żądanie standardowe czy klasyczne, wynik weryfikacji integralności jest zwracany w tym samym formacie i zawiera podobne informacje. Ocena integralności przekazuje informacje o prawidłowości urządzeń, aplikacji i kont. Serwer aplikacji może użyć otrzymanego zasobu w odszyfrowanej i zweryfikowanej ocenie, aby określić, jak najlepiej postępować w przypadku konkretnego działania lub żądania w aplikacji.

Format zwracanej oceny integralności

Ładunek to zwykły tekst JSON, który zawiera sygnały integralności oraz informacje dostarczone przez dewelopera.

Ogólna struktura ładunku jest taka:

{
  "requestDetails": { ... },
  "appIntegrity": { ... },
  "deviceIntegrity": { ... },
  "accountDetails": { ... },
  "environmentDetails": { ... }
}

Zanim sprawdzisz poszczególne wyniki oceny integralności, musisz najpierw upewnić się, że wartości w polu requestDetails są zgodne z wartościami z pierwotnej prośby. Sekcje poniżej zawierają szczegółowe opisy poszczególnych pól.

Pole Szczegóły żądania

Pole requestDetails zawiera informacje o żądaniu, w tym informacje podane przez dewelopera w polu requestHash w przypadku żądań standardowych i w polu nonce w przypadku żądań klasycznych.

W przypadku standardowych żądań do interfejsu API:

"requestDetails": {
  // Application package name this attestation was requested for.
  // Note that this field might be spoofed in the middle of the request.
  "requestPackageName": "com.package.name",
  // Request hash provided by the developer.
  "requestHash": "aGVsbG8gd29scmQgdGhlcmU",
  // The timestamp in milliseconds when the integrity token
  // was requested.
  "timestampMillis": "1675655009345"
}

Wartości te powinny być zgodne z wartościami w pierwotnej prośbie. Dlatego sprawdź część requestDetails ładunku JSON, upewniając się, że wartości requestPackageNamerequestHash są zgodne z wartościami wysłanymi w pierwotnym żądaniu, jak pokazano w tym fragmencie kodu:

Kotlin

val requestDetails = JSONObject(payload).getJSONObject("requestDetails")
val requestPackageName = requestDetails.getString("requestPackageName")
val requestHash = requestDetails.getString("requestHash")
val timestampMillis = requestDetails.getLong("timestampMillis")
val currentTimestampMillis = ...

// Ensure the token is from your app.
if (!requestPackageName.equals(expectedPackageName)
        // Ensure the token is for this specific request
    || !requestHash.equals(expectedRequestHash)
        // Ensure the freshness of the token.
    || currentTimestampMillis - timestampMillis > ALLOWED_WINDOW_MILLIS) {
        // The token is invalid! See below for further checks.
        ...
}

Java

RequestDetails requestDetails =
    decodeIntegrityTokenResponse
    .getTokenPayloadExternal()
    .getRequestDetails();
String requestPackageName = requestDetails.getRequestPackageName();
String requestHash = requestDetails.getRequestHash();
long timestampMillis = requestDetails.getTimestampMillis();
long currentTimestampMillis = ...;

// Ensure the token is from your app.
if (!requestPackageName.equals(expectedPackageName)
        // Ensure the token is for this specific request.
    || !requestHash.equals(expectedRequestHash)
        // Ensure the freshness of the token.
    || currentTimestampMillis - timestampMillis > ALLOWED_WINDOW_MILLIS) {
        // The token is invalid! See below for further checks.
        ...
}

W przypadku żądań do klasycznego interfejsu API:

"requestDetails": {
  // Application package name this attestation was requested for.
  // Note that this field might be spoofed in the middle of the
  // request.
  "requestPackageName": "com.package.name",
  // base64-encoded URL-safe no-wrap nonce provided by the developer.
  "nonce": "aGVsbG8gd29scmQgdGhlcmU",
  // The timestamp in milliseconds when the request was made
  // (computed on the server).
  "timestampMillis": "1617893780"
}

Wartości te powinny być zgodne z wartościami w pierwotnej prośbie. Dlatego sprawdź część requestDetails ładunku JSON, upewniając się, że requestPackageName i nonce są zgodne z tym, co zostało wysłane w pierwotnym żądaniu, jak pokazano w tym fragmencie kodu:

Kotlin

val requestDetails = JSONObject(payload).getJSONObject("requestDetails")
val requestPackageName = requestDetails.getString("requestPackageName")
val nonce = requestDetails.getString("nonce")
val timestampMillis = requestDetails.getLong("timestampMillis")
val currentTimestampMillis = ...

// Ensure the token is from your app.
if (!requestPackageName.equals(expectedPackageName)
        // Ensure the token is for this specific request. See 'Generate a nonce'
        // section of the doc on how to store/compute the expected nonce.
    || !nonce.equals(expectedNonce)
        // Ensure the freshness of the token.
    || currentTimestampMillis - timestampMillis > ALLOWED_WINDOW_MILLIS) {
        // The token is invalid! See below for further checks.
        ...
}

Java

JSONObject requestDetails =
    new JSONObject(payload).getJSONObject("requestDetails");
String requestPackageName = requestDetails.getString("requestPackageName");
String nonce = requestDetails.getString("nonce");
long timestampMillis = requestDetails.getLong("timestampMillis");
long currentTimestampMillis = ...;

// Ensure the token is from your app.
if (!requestPackageName.equals(expectedPackageName)
        // Ensure the token is for this specific request. See 'Generate a nonce'
        // section of the doc on how to store/compute the expected nonce.
    || !nonce.equals(expectedNonce)
        // Ensure the freshness of the token.
    || currentTimestampMillis - timestampMillis > ALLOWED_WINDOW_MILLIS) {
        // The token is invalid! See below for further checks.
        ...
}

Pole Integralność aplikacji

Pole appIntegrity zawiera informacje o pakiecie.

"appIntegrity": {
  // PLAY_RECOGNIZED, UNRECOGNIZED_VERSION, or UNEVALUATED.
  "appRecognitionVerdict": "PLAY_RECOGNIZED",
  // The package name of the app.
  // This field is populated iff appRecognitionVerdict != UNEVALUATED.
  "packageName": "com.package.name",
  // The sha256 digest of app certificates (base64-encoded URL-safe).
  // This field is populated iff appRecognitionVerdict != UNEVALUATED.
  "certificateSha256Digest": ["6a6a1474b5cbbb2b1aa57e0bc3"],
  // The version of the app.
  // This field is populated iff appRecognitionVerdict != UNEVALUATED.
  "versionCode": "42"
}

appRecognitionVerdict może mieć te wartości:

PLAY_RECOGNIZED
Aplikacja i certyfikat odpowiadają wersjom rozpowszechnianym w Google Play.
UNRECOGNIZED_VERSION
Nazwa certyfikatu lub pakietu nie odpowiada rekordom Google Play.
UNEVALUATED
Integralność aplikacji nie została określona. Pominięto niezbędny wymóg, np. urządzenie nie było wystarczająco godne zaufania.

Aby mieć pewność, że token został wygenerowany przez aplikację utworzoną przez Ciebie, sprawdź, czy integralność aplikacji jest zgodna z oczekiwaniami, jak pokazano w tym fragmencie kodu:

Kotlin

val appIntegrity = JSONObject(payload).getJSONObject("appIntegrity")
val appRecognitionVerdict = appIntegrity.getString("appRecognitionVerdict")

if (appRecognitionVerdict == "PLAY_RECOGNIZED") {
    // Looks good!
}

Java

JSONObject appIntegrity =
    new JSONObject(payload).getJSONObject("appIntegrity");
String appRecognitionVerdict =
    appIntegrity.getString("appRecognitionVerdict");

if (appRecognitionVerdict.equals("PLAY_RECOGNIZED")) {
    // Looks good!
}

Możesz też ręcznie sprawdzić nazwę pakietu aplikacji, jej wersję i certyfikaty.

Pole integralności urządzenia

Pole deviceIntegrity może zawierać pojedynczą wartość, deviceRecognitionVerdict, która ma co najmniej 1 etykietę określającą, jak dobrze urządzenie może egzekwować integralność aplikacji. Jeśli urządzenie nie spełnia kryteriów żadnej etykiety, pole deviceIntegrity pomija deviceRecognitionVerdict.

"deviceIntegrity": {
  // "MEETS_DEVICE_INTEGRITY" is one of several possible values.
  "deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"]
}

Domyślnie deviceRecognitionVerdict może zawierać:

MEETS_DEVICE_INTEGRITY
Aplikacja działa na oryginalnym i certyfikowanym urządzeniu z Androidem. W Androidzie 13 i nowszych wersjach istnieje sprzętowe potwierdzenie, że program rozruchowy urządzenia jest zablokowany, a załadowany system operacyjny Android to certyfikowany obraz producenta urządzenia.
Puste (pusta wartość)
Aplikacja działa na urządzeniu, na którym pojawiły się oznaki ataku (np. punkt zaczepienia w interfejsie API) lub naruszenia systemu (np. dostęp do roota), albo aplikacja nie działa na urządzeniu fizycznym (tylko np. na emulatorze, który nie przeszedł testów integralności Google Play).

Aby mieć pewność, że token pochodzi z zaufanego urządzenia, sprawdź, czy deviceRecognitionVerdict jest zgodny z oczekiwaniami, jak pokazano w tym fragmencie kodu:

Kotlin

val deviceIntegrity =
    JSONObject(payload).getJSONObject("deviceIntegrity")
val deviceRecognitionVerdict =
    if (deviceIntegrity.has("deviceRecognitionVerdict")) {
        deviceIntegrity.getJSONArray("deviceRecognitionVerdict").toString()
    } else {
        ""
    }

if (deviceRecognitionVerdict.contains("MEETS_DEVICE_INTEGRITY")) {
    // Looks good!
}

Java

JSONObject deviceIntegrity =
    new JSONObject(payload).getJSONObject("deviceIntegrity");
String deviceRecognitionVerdict =
    deviceIntegrity.has("deviceRecognitionVerdict")
    ? deviceIntegrity.getJSONArray("deviceRecognitionVerdict").toString()
    : "";

if (deviceRecognitionVerdict.contains("MEETS_DEVICE_INTEGRITY")) {
    // Looks good!
}

Jeśli masz problemy z tym, że urządzenie testowe nie spełnia wymagań dotyczących integralności urządzenia, upewnij się, że jest na nim zainstalowany ROM fabryczny (np. zresetuj urządzenie) i że program rozruchowy jest zablokowany. Możesz też utworzyć testy interfejsu Play Integrity API w Konsoli Play.

Etykiety urządzeń warunkowych

Jeśli Twoja aplikacja jest udostępniana w Grach Google Play na PC, element deviceRecognitionVerdict może też zawierać tę etykietę:

MEETS_VIRTUAL_INTEGRITY
Aplikacja działa w emulatorze z Androidem i Usługami Google Play. Emulator przeszedł testy integralności systemu i spełnia podstawowe wymagania dotyczące zgodności dla urządzeń z Androidem.

Opcjonalne informacje o urządzeniu i przywracanie urządzenia

Jeśli wyrazisz zgodę na otrzymywanie dodatkowych etykiet w ocenie integralności, pole deviceRecognitionVerdict może zawierać te dodatkowe etykiety:

MEETS_BASIC_INTEGRITY
Aplikacja działa na urządzeniu, które przeszło podstawowe testy integralności systemu. Program rozruchowy urządzenia może być zablokowany lub odblokowany, a stan uruchamiania może być zweryfikowany lub niezweryfikowany. Urządzenie może nie mieć certyfikatu, w którym to przypadku Google nie może zapewnić bezpieczeństwa, prywatności ani zgodności aplikacji. W przypadku Androida 13 i nowszych wersji MEETS_BASIC_INTEGRITY werdykt wymaga tylko, aby główny element zaufania atestu był dostarczany przez Google.
MEETS_STRONG_INTEGRITY
Aplikacja działa na oryginalnym i certyfikowanym urządzeniu z Androidem, które ma najnowsze aktualizacje zabezpieczeń.
  • W przypadku Androida 13 i nowszych wersji MEETS_STRONG_INTEGRITY wymagaMEETS_DEVICE_INTEGRITY aktualizacji zabezpieczeń w ciągu ostatniego roku dla wszystkich partycji urządzenia, w tym poprawki partycji systemu operacyjnego Android i poprawki partycji dostawcy.
  • W przypadku Androida 12 i starszych wersji MEETS_STRONG_INTEGRITY wymaga tylko dowodu integralności rozruchu wspieranego sprzętowo i nie wymaga, aby urządzenie miało najnowszą aktualizację zabezpieczeń. Dlatego podczas korzystania z MEETS_STRONG_INTEGRITY zalecamy uwzględnianie w polu deviceAttributes wersji pakietu Android SDK.

Pojedyncze urządzenie może zwrócić wiele etykiet urządzenia w odpowiedzi dotyczącej integralności urządzenia, jeśli zostaną spełnione kryteria każdej z nich.

Atrybuty urządzenia

Możesz też wyrazić zgodę na otrzymywanie atrybutów urządzenia, które informują o wersji pakietu Android SDK systemu Android działającego na urządzeniu. W przyszłości może zostać rozszerzona o inne atrybuty urządzenia.

Wartość wersji pakietu SDK to numer wersji pakietu Android SDK zdefiniowany w Build.VERSION_CODES. Wersja pakietu SDK nie jest sprawdzana, jeśli pominięto niezbędny wymóg. W takim przypadku pole sdkVersion nie jest ustawione, więc pole deviceAttributes jest puste. Może się tak zdarzyć, jeśli:

  • Urządzenie nie jest wystarczająco zaufane.
  • Na urządzeniu wystąpiły problemy techniczne.

Jeśli zdecydujesz się otrzymywać deviceAttributes, pole deviceIntegrity będzie zawierać to dodatkowe pole:

"deviceIntegrity": {
  "deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"],
  "deviceAttributes": {
    // 33 is one possible value, which represents Android 13 (Tiramisu).
    "sdkVersion": 33
  }
}

Jeśli wersja pakietu SDK nie zostanie oceniona, pole deviceAttributes będzie miało taką wartość:

"deviceIntegrity": {
  "deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"],
  "deviceAttributes": {}  // sdkVersion field is not set.
}

Ostatnia aktywność na urządzeniu

Możesz też włączyć funkcję „Ostatnia aktywność na urządzeniu”, która informuje, ile razy w ciągu ostatniej godziny Twoja aplikacja wysłała żądanie tokena integralności na określone urządzenie. Za pomocą tej funkcji możesz chronić swoją aplikację przed nadaktywnymi urządzeniami działającymi w nietypowy sposób mogący wskazywać na trwający atak. Możesz określić, w jakim stopniu ufasz poszczególnym poziomom ostatniej aktywności na urządzeniu, na podstawie tego, ile razy Twoja aplikacja zainstalowana na typowym urządzeniu powinna wysyłać żądanie tokena integralności w ciągu godziny.

Jeśli wyrazisz zgodę na otrzymywanie recentDeviceActivity, pole deviceIntegrity będzie zawierać 2 wartości:

"deviceIntegrity": {
  "deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"],
  "recentDeviceActivity": {
    // "LEVEL_2" is one of several possible values.
    "deviceActivityLevel": "LEVEL_2"
  }
}

Definicje deviceActivityLevel różnią się w zależności od trybu i mogą mieć jedną z tych wartości:

Poziom ostatniej aktywności na urządzeniu Standardowe żądania tokena integralności interfejsu API na tym urządzeniu w ciągu ostatniej godziny na aplikację Żądania tokena integralności klasycznego interfejsu API na tym urządzeniu w ciągu ostatniej godziny na aplikację
LEVEL_1 (najniższa) 10 lub mniej 5 lub mniej
LEVEL_2 Od 11 do 25 Od 6 do 10
LEVEL_3 26–50 Od 11 do 15
LEVEL_4 (najwyższy) Ponad 50 Ponad 15
UNEVALUATED Ostatnia aktywność na urządzeniach nie została oceniona. Może się tak zdarzyć, ponieważ:
  • Urządzenie nie jest wystarczająco zaufane.
  • Google Play nie rozpoznaje wersji aplikacji zainstalowanej na urządzeniu.
  • problemy techniczne na urządzeniu,

Wycofanie urządzenia (beta)

Możesz też włączyć przywoływanie danych z urządzenia, które umożliwia przechowywanie niektórych niestandardowych danych dotyczących poszczególnych urządzeń, które możesz niezawodnie odzyskać, gdy aplikacja zostanie ponownie zainstalowana na tym samym urządzeniu. Po wysłaniu żądania tokena integralności wykonujesz osobne wywołanie serwer-serwer, aby zmodyfikować wartości wycofania urządzenia w przypadku konkretnego urządzenia.

Jeśli wyrazisz zgodę na deviceRecall, pole deviceIntegrity będzie zawierać informacje o wycofaniu urządzenia, które zostały przez Ciebie ustawione dla konkretnego urządzenia:

"deviceIntegrity": {
  "deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"],
  "deviceRecall": {
    "values": {
      "bitFirst": true,
      "bitSecond": false,
      "bitThird": true
    },
    "writeDates": {
      // Write time in YYYYMM format in UTC.
      "yyyymmFirst": 202401,
      // Note that yyyymmSecond is not set because bitSecond is false.
      "yyyymmThird": 202310
    }
  }
}

deviceRecall jest podzielony na 2 pola:

  • values: przywróć wartości bitów, które zostały wcześniej ustawione na tym urządzeniu.
  • writeDates: przypomnij daty zapisu bitów w czasie UTC z dokładnością do roku i miesiąca. Data zapisu bitu wycofania będzie aktualizowana za każdym razem, gdy bit zostanie ustawiony na true, i usunięta, gdy bit zostanie ustawiony na false.

Jeśli informacje o wycofaniu urządzenia są niedostępne, wartość wycofania urządzenia będzie pusta:

"deviceIntegrity": {
  "deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"],
  "deviceRecall": {
    "values": {},
    "writeDates": {}
  }
}

Pole szczegółów konta

Pole accountDetails zawiera jedną wartość, appLicensingVerdict, która reprezentuje stan licencji aplikacji w Google Play na koncie użytkownika zalogowanego na urządzeniu. Jeśli konto użytkownika ma licencję Play na aplikację, oznacza to, że użytkownik pobrał ją z Google Play lub kupił ją w Google Play.

"accountDetails": {
  // This field can be LICENSED, UNLICENSED, or UNEVALUATED.
  "appLicensingVerdict": "LICENSED"
}

appLicensingVerdict może mieć jedną z tych wartości:

LICENSED
Użytkownik ma uprawnienia do korzystania z aplikacji. To znaczy, że zainstalował lub zaktualizował Twoją aplikację z Google Play na swoim urządzeniu.
UNLICENSED
Użytkownik nie ma uprawnień do korzystania z aplikacji. Może się tak zdarzyć, jeśli np. zainstaluje ją z innego urządzenia lub nie pozyska jej z Google Play. Aby rozwiązać ten problem, możesz wyświetlić użytkownikom okno GET_LICENSED.
UNEVALUATED

Szczegóły dotyczące licencji nie zostały określone, ponieważ pominięto niezbędny wymóg.

Może się tak zdarzyć z kilku powodów. Oto niektóre z nich:

  • Urządzenie nie jest wystarczająco zaufane.
  • Google Play nie rozpoznaje wersji aplikacji zainstalowanej na urządzeniu.
  • Użytkownik nie jest zalogowany w Google Play.

Aby sprawdzić, czy użytkownik ma uprawnienia do korzystania z Twojej aplikacji, sprawdź, czy wartość appLicensingVerdict jest zgodna z oczekiwaną, jak pokazano w tym fragmencie kodu:

Kotlin

val accountDetails = JSONObject(payload).getJSONObject("accountDetails")
val appLicensingVerdict = accountDetails.getString("appLicensingVerdict")

if (appLicensingVerdict == "LICENSED") {
    // Looks good!
}

Java

JSONObject accountDetails =
    new JSONObject(payload).getJSONObject("accountDetails");
String appLicensingVerdict = accountDetails.getString("appLicensingVerdict");

if (appLicensingVerdict.equals("LICENSED")) {
    // Looks good!
}

Pole szczegółów środowiska

Możesz też włączyć dodatkowe sygnały dotyczące środowiska. Sygnał ryzyka dotyczącego dostępu do aplikacji umożliwia wykrycie, czy są uruchomione inne aplikacje, które mogą przechwytywać ekran, wyświetlać nakładki lub sterować urządzeniem. Ocena Play Protect informuje, czy usługa Google Play Protect jest włączona na urządzeniu i czy wykryła znane złośliwe oprogramowanie.

Jeśli w Konsoli Google Play włączysz ocenę ryzyka dostępu do aplikacji lub ocenę Play Protect, odpowiedź interfejsu API będzie zawierać pole environmentDetails. Pole environmentDetails może zawierać 2 wartości: appAccessRiskVerdictplayProtectVerdict.

Ocena ryzyka dotyczącego dostępu do aplikacji

Gdy włączysz tę opcję, w polu environmentDetailsładunku interfejsu Play Integrity API pojawi się nowa ocena ryzyka dotyczącego dostępu do aplikacji.

{
  "requestDetails": { ... },
  "appIntegrity": { ... },
  "deviceIntegrity": { ... },
  "accountDetails": { ... },
  "environmentDetails": {
      "appAccessRiskVerdict": {
          // This field contains one or more responses, for example the following.
          "appsDetected": ["KNOWN_INSTALLED", "UNKNOWN_INSTALLED", "UNKNOWN_CAPTURING"]
      }
 }
}

Jeśli oceniono ryzyko związane z dostępem do aplikacji, pole appAccessRiskVerdict zawiera pole appsDetected z co najmniej 1 odpowiedzią. Odpowiedzi te dzielą się na 2 grupy w zależności od źródła instalacji wykrytych aplikacji:

  • Aplikacje systemowe lub aplikacje z Google Play: aplikacje zainstalowane przez Google Play lub wstępnie załadowane przez producenta urządzenia w partycji systemowej urządzenia (oznaczone symbolem FLAG_SYSTEM). Odpowiedzi dotyczące takich aplikacji mają przedrostek KNOWN_.

  • Inne aplikacje: aplikacje, które nie zostały zainstalowane przez Google Play. Nie obejmuje to aplikacji wstępnie zainstalowanych na partycji systemowej przez producenta urządzenia. Odpowiedzi dotyczące takich aplikacji są poprzedzone symbolem UNKNOWN_.

Możesz otrzymać te odpowiedzi:

KNOWN_INSTALLED, UNKNOWN_INSTALLED
Zainstalowane aplikacje są zgodne z odpowiednim źródłem instalacji.
KNOWN_CAPTURING, UNKNOWN_CAPTURING
Uruchomione są aplikacje, które mają włączone uprawnienia umożliwiające wyświetlanie ekranu podczas działania Twojej aplikacji. Nie obejmuje to zweryfikowanych usług ułatwień dostępu znanych Google Play, które działają na urządzeniu.
KNOWN_CONTROLLING, UNKNOWN_CONTROLLING
Na urządzeniu działają aplikacje, które mają włączone uprawnienia umożliwiające sterowanie urządzeniem i bezpośrednie kontrolowanie danych wejściowych w Twojej aplikacji. Mogą one służyć do przechwytywania danych wejściowych i wyjściowych aplikacji. Nie dotyczy to zweryfikowanych usług ułatwień dostępu znanych Google Play, które działają na urządzeniu.
KNOWN_OVERLAYS, UNKNOWN_OVERLAYS
Na urządzeniu działają aplikacje, które mają włączone uprawnienia umożliwiające wyświetlanie nakładek na Twoją aplikację. Nie dotyczy to zweryfikowanych usług ułatwień dostępu znanych Google Play, które działają na urządzeniu.
Puste (pusta wartość)

Ryzyko dotyczące dostępu do aplikacji nie jest oceniane, jeśli pominięto niezbędny wymóg. W tym przypadku pole appAccessRiskVerdict jest puste. Może się tak zdarzyć z kilku powodów. Oto niektóre z nich:

  • Urządzenie nie jest wystarczająco zaufane.
  • Urządzenie nie jest telefonem, tabletem ani urządzeniem składanym.
  • Urządzenie nie ma Androida 6 (poziom API 23) lub nowszego.
  • Google Play nie rozpoznaje wersji aplikacji zainstalowanej na urządzeniu.
  • Wersja Sklepu Google Play na urządzeniu jest nieaktualna.
  • Konto użytkownika nie ma licencji Play.
  • Użyto standardowego żądania z parametrem verdictOptOut.
  • Użyto żądania standardowego z wersją biblioteki interfejsu Play Integrity API, która nie obsługuje jeszcze ryzyka dotyczącego dostępu do aplikacji w przypadku żądań standardowych.

Ryzyko związane z dostępem do aplikacji automatycznie wyklucza zweryfikowane usługi ułatwień dostępu, które przeszły rozszerzoną weryfikację ułatwień dostępu w Google Play (zainstalowane przez dowolny sklep z aplikacjami na urządzeniu). „Wykluczone” oznacza, że zweryfikowane usługi ułatwień dostępu działające na urządzeniu nie będą zwracać odpowiedzi dotyczącej przechwytywania, kontrolowania ani nakładek w ocenie ryzyka związanego z dostępem aplikacji. Aby poprosić o rozszerzone sprawdzenie dostępności aplikacji w Google Play, opublikuj ją w Google Play, upewniając się, że w pliku manifestu aplikacji flaga isAccessibilityTool ma wartość „true”, lub poproś o sprawdzenie.

Przykładowe oceny ryzyka dotyczącego dostępu do aplikacji

W tabeli poniżej znajdziesz przykłady wyników oceny ryzyka związanego z dostępem do aplikacji i ich znaczenie (tabela nie zawiera wszystkich możliwych wyników):

Przykładowa odpowiedź z oceną ryzyka dotyczącego dostępu do aplikacji Interpretacja
appsDetected:
["KNOWN_INSTALLED"]
Na urządzeniu są zainstalowane tylko aplikacje rozpoznawane przez Google Play lub wstępnie załadowane na partycji systemowej przez producenta urządzenia.
Nie działają żadne aplikacje, które mogłyby spowodować uzyskanie wyników „przechwytywanie”, „kontrolowanie” lub „nakładki”.
appsDetected:
["KNOWN_INSTALLED",
"UNKNOWN_INSTALLED",
"UNKNOWN_CAPTURING"]
Na urządzeniu są zainstalowane aplikacje z Google Play lub wstępnie załadowane w partycji systemowej przez producenta urządzenia.
Uruchomione są inne aplikacje, które mają włączone uprawnienia umożliwiające wyświetlanie ekranu lub przechwytywanie innych danych wejściowych i wyjściowych.
appsDetected:
["KNOWN_INSTALLED",
"KNOWN_CAPTURING",
"UNKNOWN_INSTALLED",
"UNKNOWN_CONTROLLING"]
Uruchomione są aplikacje z Google Play lub aplikacje systemowe, które mają włączone uprawnienia umożliwiające wyświetlanie ekranu lub przechwytywanie innych danych wejściowych i wyjściowych.
 Uruchomione są też inne aplikacje z włączonymi uprawnieniami, które mogą być używane do sterowania urządzeniem i bezpośredniego kontrolowania danych wejściowych w Twojej aplikacji.
appAccessRiskVerdict: {} Ryzyko związane z dostępem do aplikacji nie zostało ocenione, ponieważ pominięto niezbędny wymóg. np. urządzenie nie było wystarczająco godne zaufania.

W zależności od poziomu ryzyka możesz zdecydować, które kombinacje ocen są akceptowalne, a w przypadku których chcesz podjąć działania. Ten fragment kodu pokazuje przykład weryfikacji, czy nie są uruchomione żadne aplikacje, które mogą rejestrować to, co widać na ekranie, lub kontrolować Twoją aplikację:

Kotlin

val environmentDetails =
    JSONObject(payload).getJSONObject("environmentDetails")
val appAccessRiskVerdict =
    environmentDetails.getJSONObject("appAccessRiskVerdict")

if (appAccessRiskVerdict.has("appsDetected")) {
    val appsDetected = appAccessRiskVerdict.getJSONArray("appsDetected").toString()
    if (!appsDetected.contains("CAPTURING") && !appsDetected.contains("CONTROLLING")) {
        // Looks good!
    }
}

Java

JSONObject environmentDetails =
    new JSONObject(payload).getJSONObject("environmentDetails");
JSONObject appAccessRiskVerdict =
    environmentDetails.getJSONObject("appAccessRiskVerdict");

if (appAccessRiskVerdict.has("appsDetected")) {
    String appsDetected = appAccessRiskVerdict.getJSONArray("appsDetected").toString()
    if (!appsDetected.contains("CAPTURING") && !appsDetected.contains("CONTROLLING")) {
        // Looks good!
    }
}
Naprawianie ocen ryzyka dotyczącego dostępu do aplikacji

W zależności od poziomu ryzyka możesz zdecydować, w przypadku których wyników oceny ryzyka dostępu do aplikacji chcesz podjąć działania, zanim użytkownik dokończy żądanie lub działanie. Po sprawdzeniu wyniku ryzyka dotyczącego dostępu do aplikacji możesz wyświetlić użytkownikowi opcjonalne komunikaty Google Play. Możesz wyświetlić komunikat CLOSE_UNKNOWN_ACCESS_RISK z prośbą o zamknięcie nieznanych aplikacji, które powodują wynik ryzyka dotyczącego dostępu do aplikacji, lub komunikat CLOSE_ALL_ACCESS_RISK z prośbą o zamknięcie wszystkich aplikacji (znanych i nieznanych), które powodują wynik ryzyka dotyczącego dostępu do aplikacji.

Ocena Play Protect

Gdy włączysz tę opcję, w polu environmentDetailsładunku interfejsu Play Integrity API pojawi się ocena dotycząca Play Protect:

"environmentDetails": {
  "playProtectVerdict": "NO_ISSUES"
}

playProtectVerdict może mieć jedną z tych wartości:

NO_ISSUES
Usługa Play Protect jest włączona i nie wykryła na urządzeniu żadnych problemów z aplikacjami.
NO_DATA
Ochrona Play Protect jest włączona, ale skanowanie nie zostało jeszcze przeprowadzone. Urządzenie lub aplikacja Sklep Play mogły zostać niedawno zresetowane.
POSSIBLE_RISK
Ochrona Play Protect jest wyłączona.
MEDIUM_RISK
Usługa Play Protect jest włączona i wykryła zainstalowane na urządzeniu potencjalnie szkodliwe aplikacje.
HIGH_RISK
Usługa Play Protect jest włączona i wykryła na urządzeniu niebezpieczne aplikacje.
UNEVALUATED

Opinia Play Protect nie została sprawdzona.

Może się tak zdarzyć z kilku powodów. Oto niektóre z nich:

  • Urządzenie nie jest wystarczająco zaufane.
  • Konto użytkownika nie ma licencji Play.

Wskazówki dotyczące korzystania z oceny Play Protect

Serwer backendu aplikacji może następnie podjąć odpowiednie działania na podstawie Twojej tolerancji ryzyka. Oto kilka sugestii i potencjalnych działań użytkowników:

NO_ISSUES
Play Protect jest włączony i nie wykrył żadnych problemów, więc nie musisz podejmować żadnych działań.
POSSIBLE_RISKNO_DATA
Gdy otrzymasz te wyniki, poproś użytkownika o sprawdzenie, czy Play Protect jest włączony i czy przeprowadził skanowanie. NO_DATA powinien pojawiać się tylko w rzadkich przypadkach.
MEDIUM_RISKHIGH_RISK
W zależności od poziomu tolerancji ryzyka możesz poprosić użytkownika o uruchomienie Play Protect i podjęcie działań w odpowiedzi na ostrzeżenia Play Protect. Jeśli użytkownik nie spełnia tych wymagań, możesz zablokować mu dostęp do działania serwera.