Вердикты о честности

На этой странице описано, как интерпретировать и работать с возвращаемым заключением о целостности. Независимо от того, отправляете ли вы стандартный или классический API-запрос, заключение о целостности возвращается в одном и том же формате и с аналогичным содержимым. Заключение о целостности передает информацию о действительности устройств, приложений и учетных записей. Сервер вашего приложения может использовать полученную полезную нагрузку в расшифрованном, проверенном виде, чтобы определить, как лучше всего продолжить выполнение конкретного действия или запроса в вашем приложении.

Формат вынесения решения по вопросу о добросовестности

Полезная нагрузка представляет собой текстовый JSON и содержит сигналы целостности наряду с информацией, предоставленной разработчиком.

Общая структура полезной нагрузки выглядит следующим образом:

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

Перед проверкой каждого результата проверки целостности необходимо сначала убедиться, что значения в поле requestDetails соответствуют значениям исходного запроса. В следующих разделах каждое поле описано более подробно.

Поле с подробными сведениями о запросе

Поле requestDetails содержит информацию о запросе, включая предоставленную разработчиком информацию в requestHash для стандартных запросов и nonce для классических запросов.

Для стандартных запросов 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"
}

Эти значения должны совпадать со значениями исходного запроса. Поэтому проверьте часть requestDetails в JSON-данных, убедившись, что requestPackageName и requestHash совпадают с тем, что было отправлено в исходном запросе, как показано в следующем фрагменте кода:

Котлин

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.
        ...
}

Для классических запросов 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"
}

Эти значения должны совпадать со значениями исходного запроса. Поэтому проверьте часть requestDetails в JSON-данных, убедившись, что requestPackageName и nonce совпадают с теми, что были отправлены в исходном запросе, как показано в следующем фрагменте кода:

Котлин

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.
        ...
}

Поле целостности приложения

Поле appIntegrity содержит информацию, относящуюся к пакету.

"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 может принимать следующие значения:

PLAY_RECOGNIZED
Приложение и сертификат соответствуют версиям, распространяемым через Google Play.
UNRECOGNIZED_VERSION
Название сертификата или пакета не соответствует записям Google Play.
UNEVALUATED
Целостность приложения не оценивалась. Было упущено необходимое требование, например, устройство не обладало достаточной надежностью.

Чтобы убедиться, что токен был сгенерирован приложением, созданным вами, проверьте целостность приложения на соответствие ожидаемым параметрам, как показано в следующем фрагменте кода:

Котлин

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!
}

Вы также можете проверить имя пакета приложения, версию приложения и сертификаты приложения вручную.

Поле целостности устройства

Поле deviceIntegrity может содержать одно значение, deviceRecognitionVerdict , которое имеет одну или несколько меток, определяющих, насколько хорошо устройство может обеспечивать целостность приложения. Если устройство не соответствует критериям ни одной из меток, то значение deviceRecognitionVerdict в поле deviceIntegrity отсутствует.

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

По умолчанию deviceRecognitionVerdict может содержать следующее:

MEETS_DEVICE_INTEGRITY
Приложение работает на подлинном и сертифицированном устройстве Android. На устройствах с Android 13 и выше имеется аппаратное подтверждение того, что загрузчик устройства заблокирован, а загруженная ОС Android представляет собой сертифицированный производителем устройства образ.
Пустое значение (пустой символ)
Приложение работает на устройстве, имеющем признаки атаки (например, перехват API) или компрометации системы (например, рутирование), либо приложение работает не на физическом устройстве (например, на эмуляторе, не прошедшем проверку целостности Google Play).

Чтобы убедиться, что токен получен от надежного устройства, проверьте, соответствует ли значение deviceRecognitionVerdict ожидаемому, как показано в следующем фрагменте кода:

Котлин

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!
}

Если у вас возникли проблемы с проверкой целостности устройства на тестовом устройстве, убедитесь, что установлена ​​заводская прошивка (например, путем сброса устройства) и что загрузчик заблокирован. Вы также можете создавать тесты Play Integrity API в своей консоли Play .

Условные метки устройств

Если ваше приложение выпускается в Google Play Games для ПК , deviceRecognitionVerdict также может содержать следующую метку:

MEETS_VIRTUAL_INTEGRITY
Приложение работает на эмуляторе Android с использованием сервисов Google Play. Эмулятор проходит проверку целостности системы и соответствует основным требованиям совместимости с Android.

Дополнительная информация об устройстве и функция вызова устройства (по желанию)

В рамках многоуровневой стратегии обеспечения целостности вы можете включить получение дополнительных меток для устройств. Если вы включите получение дополнительных меток в заключение о целостности, deviceRecognitionVerdict может содержать следующие дополнительные метки:

MEETS_BASIC_INTEGRITY
Приложение работает на устройстве, прошедшем базовые проверки целостности системы. Загрузчик устройства может быть заблокирован или разблокирован, а состояние загрузки может быть подтверждено или нет. Устройство может не быть сертифицировано, в этом случае Google не может предоставить никаких гарантий безопасности, конфиденциальности или совместимости приложения. На Android 13 и выше для выполнения условия MEETS_BASIC_INTEGRITY требуется лишь предоставление корневого сертификата доверия от Google.
MEETS_STRONG_INTEGRITY
Приложение работает на подлинном и сертифицированном устройстве Android с недавним обновлением безопасности.
  • На Android 13 и выше для достижения вердикта MEETS_STRONG_INTEGRITY требуется наличие MEETS_DEVICE_INTEGRITY и обновлений безопасности за последний год для всех разделов устройства, включая патч для раздела ОС Android и патч для раздела поставщика.
  • В Android 12 и более ранних версиях для подтверждения целостности загрузки требуется только аппаратное обеспечение, и наличие на устройстве недавнего обновления MEETS_STRONG_INTEGRITY не является обязательным. Поэтому при использовании MEETS_STRONG_INTEGRITY рекомендуется также учитывать версию Android SDK в поле deviceAttributes .

Если для одного устройства выполняется каждый из критериев, указанных в вердикте о целостности устройства, оно вернет несколько меток.

Атрибуты устройства

Также можно включить атрибуты устройства, которые указывают версию Android SDK операционной системы Android, работающей на устройстве. Версия Android SDK полезна для различения устройств, работающих под управлением Android 13 и выше, и устройств, работающих под управлением более старых версий Android SDK, в рамках многоуровневой стратегии контроля . В будущем эта функция может быть расширена за счет других атрибутов устройства.

Значение версии SDK — это номер версии Android SDK, определенный в Build.VERSION_CODES . Версия SDK не вычисляется, если не выполнено необходимое условие. В этом случае поле sdkVersion не задано; следовательно, поле deviceAttributes пустое. Это может произойти по следующим причинам:

  • Данное устройство недостаточно надежно.
  • В устройстве возникли технические неполадки.

Если вы согласитесь получать данные deviceAttributes , поле deviceIntegrity будет содержать следующее дополнительное поле:

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

Если версия SDK не будет оценена, поле deviceAttributes будет установлено следующим образом:

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

Последние данные об активности устройств

Вы также можете включить отображение активности устройства за последний час, которое показывает, сколько раз ваше приложение запрашивало токен целостности на конкретном устройстве. Использование активности устройства за последний час позволяет защитить ваше приложение от неожиданно активных устройств, которые могут указывать на активную атаку. Вы можете определить, насколько доверять каждому уровню активности устройства за последний час, исходя из того, сколько раз, по вашим ожиданиям, ваше приложение, установленное на типичном устройстве, будет запрашивать токен целостности каждый час.

Если вы включите получение информации recentDeviceActivity , поле deviceIntegrity будет содержать два значения:

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

Значения параметра deviceActivityLevel различаются в зависимости от режима и могут принимать одно из следующих значений:

Уровень активности устройства за последнее время Стандартные запросы токенов целостности API на этом устройстве за последний час для каждого приложения. Запросы на получение токена целостности классического API на этом устройстве за последний час для каждого приложения
LEVEL_1 (самый низкий) 10 или меньше 5 или меньше
LEVEL_2 От 11 до 25 лет От 6 до 10
LEVEL_3 От 26 до 50 лет В возрасте от 11 до 15 лет
LEVEL_4 (самый высокий) Более 50 Более 15
UNEVALUATED Недавняя активность устройства не была оценена. Это могло произойти по следующим причинам:
  • Данное устройство недостаточно надежно.
  • Версия приложения, установленного на вашем устройстве, неизвестна Google Play.
  • Технические неполадки в устройстве.

Отзыв устройства (бета-версия)

Вы также можете включить функцию восстановления данных с устройства , которая позволяет сохранять некоторые пользовательские данные для каждого устройства на конкретных устройствах, которые вы сможете надежно восстановить при повторной установке вашего приложения на том же устройстве. После запроса токена целостности вы выполняете отдельный вызов между серверами для изменения значений восстановления данных с устройства для конкретного устройства.

Если вы включите функцию deviceRecall , поле deviceIntegrity будет содержать информацию об отзыве устройства, которую вы установили для конкретного устройства:

"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 разделён на два поля:

  • values : Вспомните битовые значения, которые вы ранее установили для этого устройства.
  • writeDates : Восстанавливает даты записи битов в формате UTC с точностью до года и месяца. Дата записи бита восстановления будет обновляться каждый раз, когда бит устанавливается в true , и удаляться, когда бит устанавливается в false .

В случае недоступности информации о восстановлении устройства значение восстановления будет пустым:

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

Поле "Информация об учетной записи"

Поле accountDetails содержит единственное значение, appLicensingVerdict , которое отображает статус лицензирования приложения в Google Play для учетной записи пользователя, вошедшего в систему на устройстве. Если у учетной записи пользователя есть лицензия Play для приложения, это означает, что он скачал или купил его в Google Play.

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

appLicensingVerdict может принимать одно из следующих значений:

LICENSED
У пользователя есть права на использование приложения. Другими словами, пользователь установил или обновил ваше приложение из Google Play на своем устройстве.
UNLICENSED
У пользователя нет прав на использование приложения. Это происходит, например, когда пользователь устанавливает ваше приложение через сторонние ресурсы или не загружает его из Google Play. Для решения этой проблемы вы можете показать пользователям диалоговое окно GET_LICENSED .
UNEVALUATED

Информация о лицензировании не была рассмотрена, поскольку было упущено необходимое требование.

Это может произойти по нескольким причинам, в том числе по следующим:

  • Данное устройство недостаточно надежно.
  • Версия приложения, установленного на вашем устройстве, неизвестна Google Play.
  • Пользователь не авторизован в Google Play.

Чтобы проверить, имеет ли пользователь право на использование вашего приложения, убедитесь, что значение appLicensingVerdict соответствует ожидаемому, как показано в следующем фрагменте кода:

Котлин

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!
}

Поле с подробными сведениями об окружающей среде

Вы также можете включить дополнительные сигналы об окружающей среде. Функция оценки риска доступа приложения сообщает вашему приложению, запущены ли другие приложения, которые могут быть использованы для захвата экрана, отображения наложений или управления устройством. Результат проверки Play Protect показывает, включена ли функция Google Play Protect на устройстве и обнаружено ли в ней известное вредоносное ПО.

Если вы выбрали вердикт App Access Risk или Play Protect в консоли Google Play, то ваш ответ API будет включать поле environmentDetails . Поле environmentDetails может содержать два значения: appAccessRiskVerdict и playProtectVerdict .

Вердикт по риску доступа к приложению

После включения поле environmentDetails в полезной нагрузке API Play Integrity будет содержать новый вердикт по риску доступа к приложению.

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

Если была проведена оценка риска доступа к приложению, поле appAccessRiskVerdict содержит поле appsDetected с одним или несколькими ответами. Эти ответы попадают в одну из двух групп в зависимости от источника установки обнаруженных приложений:

  • Приложения Play или системные приложения : приложения, установленные Google Play или предустановленные производителем устройства в системном разделе устройства (обозначаются флагом FLAG_SYSTEM ). Ответы для таких приложений имеют префикс KNOWN_ .

  • Другие приложения : приложения, не установленные через Google Play. Сюда не входят приложения, предустановленные производителем устройства в системном разделе. Ответы для таких приложений начинаются с префикса UNKNOWN_ .

В ответ могут быть получены следующие данные:

KNOWN_INSTALLED , UNKNOWN_INSTALLED
Установлены приложения, соответствующие источнику установки.
KNOWN_CAPTURING , UNKNOWN_CAPTURING
На устройстве запущены приложения с включенными разрешениями, которые могут использоваться для просмотра экрана во время работы вашего приложения. Это не относится к проверенным сервисам специальных возможностей, известным Google Play и работающим на устройстве.
KNOWN_CONTROLLING , UNKNOWN_CONTROLLING
На устройстве запущены приложения с включенными разрешениями, которые могут использоваться для управления устройством и непосредственного управления вводом данных в ваше приложение, а также для захвата входных и выходных данных вашего приложения. Это исключает любые проверенные сервисы специальных возможностей, известные Google Play и работающие на устройстве.
KNOWN_OVERLAYS , UNKNOWN_OVERLAYS
На устройстве запущены приложения с включенными разрешениями, которые могут использоваться для отображения наложений поверх вашего приложения. Это не относится к проверенным сервисам специальных возможностей, известным Google Play и работающим на устройстве.
Пустое значение (пустой символ)

Оценка риска доступа к приложению не производится, если не выполнено необходимое условие. В этом случае поле appAccessRiskVerdict пустое. Это может произойти по нескольким причинам, в том числе по следующим:

  • Данное устройство недостаточно надежно.
  • Данное устройство не является телефоном, планшетом или складным устройством.
  • На устройстве установлена ​​не версия Android 6 (уровень API 23) или выше.
  • Версия приложения, установленного на вашем устройстве, неизвестна Google Play.
  • Версия магазина Google Play на устройстве устарела.
  • У учетной записи пользователя отсутствует лицензия Play.
  • Для запроса использовался стандартный запрос с параметром verdictOptOut .
  • Для запроса использовался стандартный запрос с версией библиотеки Play Integrity API, которая пока не поддерживает обработку рисков доступа к приложению для стандартных запросов.

Оценка риска доступа к приложению автоматически исключает проверенные службы специальных возможностей, прошедшие расширенную проверку доступности в Google Play (установленные любым магазином приложений на устройстве). «Исключено» означает, что проверенные службы специальных возможностей, работающие на устройстве, не будут возвращать ответы типа «захват», «управление» или «наложения» в оценке риска доступа к приложению. Чтобы запросить расширенную проверку доступности в Google Play для вашего приложения, опубликуйте его в Google Play, убедившись, что в манифесте вашего приложения установлен флаг isAccessibilityTool со значением true, или запросите проверку .

Примеры заключений о рисках доступа к приложению

В таблице ниже приведены примеры решений суда о риске доступа к приложению и их значения (в таблице перечислены не все возможные результаты):

Пример ответа на вердикт о риске доступа к приложению Интерпретация
appsDetected:
["KNOWN_INSTALLED"]
Установлены только те приложения, которые распознаются Google Play или предустановлены в системном разделе производителем устройства.
В настоящее время не запущены никакие приложения, которые могли бы привести к таким результатам, как захват, управление или наложение изображений.
appsDetected:
["KNOWN_INSTALLED",
"UNKNOWN_INSTALLED",
"UNKNOWN_CAPTURING"]
Существуют приложения, установленные из Google Play или предустановленные производителем устройства в системном разделе.
Запущены и другие приложения, имеющие включенные разрешения, которые могут использоваться для просмотра экрана или захвата других входных и выходных данных.
appsDetected:
["KNOWN_INSTALLED",
"KNOWN_CAPTURING",
"UNKNOWN_INSTALLED",
"UNKNOWN_CONTROLLING"]
В системе или в Play Store запущены приложения с включенными разрешениями, которые могут использоваться для просмотра экрана или захвата других входных и выходных данных.
Также запущены другие приложения с включенными разрешениями, которые можно использовать для управления устройством и непосредственного управления вводом данных в ваше приложение.
appAccessRiskVerdict: {} Риск доступа к приложению не оценивается, поскольку не было выполнено необходимое условие. Например, устройство оказалось недостаточно надежным.

В зависимости от уровня риска вы можете решить, какие комбинации вердиктов допустимы для дальнейших действий, а по каким вердиктам вы хотите предпринять какие-либо действия. Следующий фрагмент кода иллюстрирует пример проверки отсутствия запущенных приложений, которые могли бы захватывать экран или управлять вашим приложением:

Котлин

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!
    }
}
Устранение рисков доступа к приложению. Вердикты.

В зависимости от уровня риска вы можете определить, на какие ошибки доступа к приложению следует реагировать, прежде чем разрешить пользователю завершить запрос или действие. После проверки ошибки доступа к приложению пользователю можно показать дополнительные подсказки Google Play. Вы можете показать CLOSE_UNKNOWN_ACCESS_RISK , чтобы попросить пользователя закрыть неизвестные приложения, вызвавшие ошибку доступа к приложению, или CLOSE_ALL_ACCESS_RISK , чтобы попросить пользователя закрыть все приложения (известные и неизвестные), вызвавшие ошибку доступа к приложению.

Вердикт по игре Play Protect

После включения поле environmentDetails в полезной нагрузке API Play Integrity будет содержать заключение Play Protect:

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

playProtectVerdict может принимать одно из следующих значений:

NO_ISSUES
Функция Play Protect включена, и никаких проблем с приложениями на устройстве обнаружено не было.
NO_DATA
Функция Play Protect включена, но сканирование еще не выполнялось. Возможно, устройство или приложение Play Store были недавно сброшены до заводских настроек.
POSSIBLE_RISK
Функция Play Protect отключена.
MEDIUM_RISK
Функция Play Protect включена и обнаружила потенциально вредоносные приложения, установленные на устройстве.
HIGH_RISK
Функция Play Protect включена и обнаружила на устройстве опасные приложения.
UNEVALUATED

Оценка эффективности функции Play Protect не проводилась.

Это может произойти по нескольким причинам, в том числе по следующим:

  • Данное устройство недостаточно надежно.
  • У учетной записи пользователя отсутствует лицензия Play.

Инструкция по использованию решения Play Protect

Серверная часть вашего приложения может принимать решения о дальнейших действиях, исходя из вашей допустимой степени риска. Вот несколько предложений и возможных действий пользователя:

NO_ISSUES
Функция Play Protect включена и не обнаружила никаких проблем, поэтому никаких действий от пользователя не требуется.
POSSIBLE_RISK и NO_DATA
Получив такие результаты, попросите пользователя проверить, включена ли функция Play Protect и выполнено ли сканирование. NO_DATA должно появляться только в редких случаях.
MEDIUM_RISK и HIGH_RISK
В зависимости от вашей терпимости к риску, вы можете попросить пользователя запустить Play Protect и принять меры в ответ на предупреждения Play Protect. Если пользователь не может выполнить эти требования, вы можете заблокировать ему доступ к серверу.