حکم‌های تمامیت

این صفحه نحوه تفسیر و کار با حکم تمامیت برگشتی را شرح می‌دهد. چه درخواست استاندارد API داشته باشید چه درخواست کلاسیک API، حکم تمامیت با همان قالب و محتوای مشابه برگردانده می‌شود. حکم تمامیت اطلاعاتی درباره اعتبار دستگاه‌ها، برنامه‌ها، و حساب‌ها ارائه می‌دهد. سرور برنامه‌تان می‌تواند از محتوای پیام حاصل در حکم رمزگشایی‌شده و درستی‌سنجی‌شده استفاده کند تا بهترین روش را برای ادامه دادن کنش یا درخواست خاصی در برنامه‌تان تعیین کند.

قالب حکم تمامیت برگشتی

پایه‌بار JSON نوشتار ساده است و در کنار اطلاعات ارائه‌شده توسط توسعه‌دهنده، حاوی نشان‌های تمامیت است.

ساختار کلی بارگیری به‌صورت زیر است:

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

ترتیب فیلدها در پایه‌بار JSON تضمین نمی‌شود. ابتدا باید بررسی کنید که مقادیر فیلد requestDetails با مقادیر درخواست اصلی مطابقت داشته باشد، سپس هر حکم تمامیت را بررسی کنید. بخش‌های زیر هر فیلد را با جزئیات بیشتری توضیح می‌دهد.

فیلد جزئیات درخواست

فیلد requestDetails حاوی اطلاعاتی درباره درخواست است، ازجمله اطلاعات ارائه‌شده توسط توسعه‌دهنده در requestHash برای درخواست‌های استاندارد و در nonce برای درخواست‌های کلاسیک.

برای درخواست‌های استاندارد میانای برنامه‌سازی کاربردی:

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

جاوا

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

برای درخواست‌های کلاسیک میانای برنامه‌سازی کاربردی:

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

جاوا

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

فیلد جزئیات حساب

فیلد 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!
}

جاوا

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

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

فیلد تمامیت برنامه

فیلد 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!
}

جاوا

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

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

همچنین می‌توانید نام بسته برنامه، نسخه برنامه، و گواهینامه‌های برنامه را به‌صورت دستی بررسی کنید.

فیلد تمامیت دستگاه

فیلد deviceIntegrity می‌تواند حاوی یک مقدار واحد، deviceRecognitionVerdict، باشد که یک یا چند برچسب دارد و نشان می‌دهد دستگاه تا چه اندازه می‌تواند تمامیت برنامه را اعمال کند. اگر دستگاهی با معیارهای هیچ‌یک از برچسب‌ها مطابقت نداشته باشد، فیلد deviceIntegrity‏ deviceRecognitionVerdict را حذف می‌کند.

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

جاوا

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 برای رایانه منتشر می‌شود، deviceRecognitionVerdict می‌تواند حاوی برچسب زیر نیز باشد:

MEETS_VIRTUAL_INTEGRITY
برنامه در شبیه‌ساز Android با پشتیبانی خدمات Google Play اجرا می‌شود. شبیه‌ساز بررسی‌های تمامیت سیستم را با موفقیت پشت سر می‌گذارد و الزامات سازگاری اصلی Android را برآورده می‌کند.

اطلاعات اختیاری دستگاه و به‌خاطرآوری دستگاه

می‌توانید برای دریافت برچسب‌های اختیاری دستگاه به‌عنوان بخشی از استراتژی اجرای چندسطحی موافقت کنید. اگر با دریافت برچسب‌های اضافی در حکم تمامیت موافقت کنید، deviceRecognitionVerdict می‌تواند حاوی برچسب‌های اضافی زیر باشد:

MEETS_BASIC_INTEGRITY
برنامه در دستگاهی اجرا می‌شود که در بررسی‌های یکپارچگی سیستم موفق عمل می‌کند. قفل bootloader دستگاه می‌تواند باز یا بسته باشد و وضعیت راه‌اندازی می‌تواند درستی‌سنجی‌شده یا درستی‌سنجی‌نشده باشد. ممکن است دستگاه گواهینامه نداشته باشد، در این صورت 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 را نیز در فیلد deviceAttributes درنظر بگیرید.

اگر هریک از معیارهای برچسب برآورده شود، یک دستگاه واحد چندین برچسب دستگاه را در حکم تمامیت دستگاه برمی‌گرداند.

ویژگی‌های دستگاه

همچنین می‌توانید با مشخصه‌های دستگاه موافقت کنید که نسخه کیت توسعه نرم‌افزار Android سیستم‌عامل Android درحال اجرا در دستگاه را نشان می‌دهد. نسخه کیت توسعه نرم‌افزار Android برای تمایز بین دستگاه‌های دارای Android 13 و بالاتر و دستگاه‌های دارای نسخه‌های پایین‌تر کیت توسعه نرم‌افزار Android به‌عنوان بخشی از استراتژی اجرای طبقه‌بندی‌شده مفید است. در آینده، ممکن است با ویژگی‌های دستگاه دیگر گسترش یابد.

مقدار نسخه کیت توسعه نرم‌افزار شماره نسخه کیت توسعه نرم‌افزار Android است که در Build.VERSION_CODES تعریف شده است. اگر یکی از الزامات ضروری رعایت نشده باشد، نسخه کیت توسعه نرم‌افزار ارزیابی نمی‌شود. در این مورد، فیلد sdkVersion تنظیم نشده است؛ بنابراین، فیلد deviceAttributes خالی است. این اتفاق ممکن است به دلایل زیر رخ دهد:

  • دستگاه به‌اندازه کافی قابل‌اعتماد نیست.
  • مشکلات فنی در دستگاه وجود داشت.

اگر موافقت کنید deviceAttributes را دریافت کنید، فیلد deviceIntegrity فیلد اضافی زیر را خواهد داشت:

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

درصورتی‌که نسخه کیت توسعه نرم‌افزار ارزیابی نشود، فیلد 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 بین حالت‌ها متفاوت است و می‌تواند یکی از مقادیر زیر را داشته باشد:

سطح فعالیت اخیر دستگاه درخواست‌های کد تمامیت «میانای برنامه‌سازی کاربردی استاندارد» در این دستگاه در ساعت گذشته برای هر برنامه درخواست‌های کد تمامیت «میانای برنامه‌سازی کاربردی کلاسیک» در این دستگاه در ساعت گذشته برای هر برنامه
‫LEVEL_1 (کمترین) 10 یا کمتر ‫۵ یا کمتر
LEVEL_2 بین ۱۱ تا ۲۵ بین ۶ تا ۱۰
LEVEL_3 بین ۲۶ و ۵۰ بین ۱۱ و ۱۵
‫LEVEL_4 (بالاترین) بیشتر از ۵۰ بیشتر از ۱۵
UNEVALUATED فعالیت اخیر دستگاه ارزیابی نشد. این اتفاق ممکن است به‌دلیل موارد زیر رخ دهد:
  • دستگاه به‌اندازه کافی قابل‌اعتماد نیست.
  • نسخه برنامه نصب‌شده در دستگاه برای Google Play ناشناخته است.
  • برنامه درخواست‌کننده پروانه ندارد (در Android 13 و بالاتر).
  • مشکلات فنی در دستگاه.

به‌خاطرآوری دستگاه (نسخه بتا)

همچنین می‌توانید با فراخوانی دستگاه موافقت کنید. این ویژگی به شما امکان می‌دهد برخی‌از داده‌های سفارشی هر دستگاه را در دستگاه‌های خاصی ذخیره کنید و وقتی برنامه‌تان بعداً در همان دستگاه بازنصب می‌شود، بتوانید این داده‌ها را با اطمینان بازیابی کنید. پس‌از درخواست کردن برای دریافت رمز تمامیت، برای اصلاح مقادیر فراخوانی دستگاه برای دستگاهی خاص، تماس سرور به سرور جداگانه‌ای برقرار می‌کنید.

اگر با 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: تاریخ‌های نوشتن بیت را به زمان هماهنگ جهانی با دقت سال و ماه به‌یاد بیاور. تاریخ نوشتن یک بیت فراخوانی هر بار که بیت روی true تنظیم شود به‌روزرسانی می‌شود و زمانی که بیت روی false تنظیم شود حذف می‌شود.

در مواردی که اطلاعات به‌یادآوری دستگاه دردسترس نباشد، مقدار به‌یادآوری دستگاه خالی خواهد بود:

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

فیلد جزئیات محیط

همچنین می‌توانید با سیگنال‌های اضافی درباره محیط موافقت کنید. «خطر دسترسی به برنامه» به برنامه شما اطلاع می‌دهد که آیا برنامه‌های دیگری که می‌توانند برای ضبط صفحه‌نمایش، نمایش رونهاد، یا کنترل دستگاه استفاده شوند درحال اجرا هستند یا نه. حکم «سپر ایمنی Play» به شما می‌گوید که آیا «سپر ایمنی Google Play» در دستگاه فعال است و آیا بدافزار شناخته‌شده‌ای پیدا کرده است یا نه.

اگر با حکم «خطر دسترسی به برنامه» یا حکم «سپر ایمنی Play» در «کنسول Google Play» موافقت کرده باشید، پاسخ API شما شامل فیلد environmentDetails خواهد بود. فیلد environmentDetails می‌تواند دو مقدار appAccessRiskVerdict و playProtectVerdict را داشته باشد.

حکم خطر دسترسی به برنامه

پس‌از فعال شدن، فیلد environmentDetails در Play Integrity API بار حاوی حکم جدید خطر دسترسی به برنامه خواهد بود.

{
  "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 (سطح میانای برنامه کاربردی ۲۳) یا بالاتر را اجرا نمی‌کند.
  • نسخه برنامه نصب‌شده در دستگاه برای Google Play ناشناخته است.
  • نسخه «فروشگاه Google Play» در دستگاه قدیمی است.
  • حساب کاربری مجوز Play ندارد.
  • از درخواست استاندارد با پارامتر verdictOptOut استفاده شد.
  • درخواستی استاندارد با نسخه کتابخانه Play Integrity API استفاده شده است که هنوز از خطر دسترسی به برنامه برای درخواست‌های استاندارد پشتیبانی نمی‌کند.

خطر دسترسی برنامه به‌طور خودکار خدمات دسترس‌پذیری تأییدشده‌ای را که از بررسی دسترس‌پذیری بهبودیافته Google Play عبور کرده‌اند (نصب‌شده توسط هر فروشگاه برنامه‌ای در دستگاه) مستثنا می‌کند. «مستثناشده» یعنی خدمات دسترس‌پذیری تأییدشده‌ای که در دستگاه اجرا می‌شود، در حکم خطر دسترسی به برنامه، پاسخ ضبط، کنترل، یا رونهاد برنمی‌گرداند. برای درخواست مرور دسترس‌پذیری بهبودیافته Google Play برای برنامه دسترس‌پذیری‌تان، آن را در Google Play منتشر کنید و مطمئن شوید که پرچم isAccessibilityTool در مانیفست برنامه‌تان روی درست تنظیم شده باشد، یا درخواست مرور کنید.

نمونه حکم‌های خطر دسترسی به برنامه

جدول زیر چند نمونه از حکم‌های خطر دسترسی برنامه و معنای آن‌ها را ارائه می‌دهد (این جدول همه نتایج ممکن را فهرست نمی‌کند):

نمونه پاسخ حکم خطر دسترسی به برنامه تفسیر
appsDetected:
["KNOWN_INSTALLED"]
فقط برنامه‌هایی نصب شده‌اند که Google Play آن‌ها را تشخیص می‌دهد یا سازنده دستگاه آن‌ها را در پارتیشن سیستم ازپیش بارگذاری کرده است.
هیچ برنامه‌ای درحال اجرا نیست که منجر به صدور حکم‌های ضبط، کنترل، یا رونهاد شود.
appsDetected:
["KNOWN_INSTALLED",
"UNKNOWN_INSTALLED",
"UNKNOWN_CAPTURING"]
برنامه‌هایی وجود دارند که Google Play نصب کرده است یا سازنده دستگاه آن‌ها را ازقبل در پارتیشن سیستم بارگذاری کرده است.
برنامه‌های دیگری درحال اجرا هستند و اجازه‌هایی دارند که می‌توان از آن‌ها برای مشاهده صفحه‌نمایش یا ضبط ورودی‌ها و بروندادهای دیگر استفاده کرد.
appsDetected:
["KNOWN_INSTALLED",
"KNOWN_CAPTURING",
"UNKNOWN_INSTALLED",
"UNKNOWN_CONTROLLING"]
برنامه‌های سیستم یا Play درحال اجرا هستند که اجازه‌هایی دارند که می‌تواند برای مشاهده صفحه‌نمایش یا ضبط ورودی‌ها و خروجی‌های دیگر استفاده شود.
برنامه‌های دیگری هم درحال اجرا هستند که اجازه‌هایی دارند که می‌توان از آن‌ها برای کنترل دستگاه و کنترل مستقیم ورودی‌های برنامه شما استفاده کرد.
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!
    }
}

جاوا

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»

پس‌از فعال شدن، فیلد environmentDetails در Play Integrity API بار حاوی حکم Play Protect خواهد بود:

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

‫playProtectVerdict می‌تواند یکی از مقادیر زیر را داشته باشد:

NO_ISSUES
«سپر ایمنی Play» روشن است و هیچ مشکلی در برنامه‌های دستگاه پیدا نکرده است.
NO_DATA
«سپر ایمنی Play» روشن است اما هنوز هیچ اسکنری انجام نشده است. دستگاه یا برنامه «فروشگاه Play» ممکن است اخیراً بازنشانی شده باشد.
POSSIBLE_RISK
«سپر ایمنی Play» خاموش است.
MEDIUM_RISK
«سپر ایمنی Play» روشن است و برنامه‌های بالقوه مضری را که در دستگاه نصب شده‌اند پیدا کرده است.
HIGH_RISK
«سپر ایمنی Play» روشن است و برنامه‌های خطرناکی را که در دستگاه نصب شده‌اند پیدا کرده است.
UNEVALUATED

حکم «سپر ایمنی Play» ارزیابی نشده است.

این اتفاق می‌تواند به دلایل مختلفی رخ دهد، ازجمله موارد زیر:

  • دستگاه به‌اندازه کافی قابل‌اعتماد نیست.
  • حساب کاربری مجوز Play ندارد.

راهنمایی درباره استفاده از حکم «سپر ایمنی Play»

سرور زیرینه برنامه‌تان می‌تواند براساس حکم و براساس میزان تحمل ریسک شما تصمیم بگیرد چگونه عمل کند. در اینجا چند پیشنهاد و کنش کاربر بالقوه ارائه شده است:

NO_ISSUES
«سپر ایمنی Play» روشن است و مشکلی پیدا نکرده است، بنابراین کاربر نیازی به اقدام ندارد.
‫POSSIBLE_RISK و NO_DATA
هنگام دریافت این حکم‌ها، از کاربر بخواهید بررسی کند که «سپر ایمنی Play» روشن باشد و اسکن انجام داده باشد. NO_DATA باید فقط در شرایط نادر ظاهر شود.
‫MEDIUM_RISK و HIGH_RISK
بسته به میزان تحمل خطر، می‌توانید از کاربر بخواهید «سپر ایمنی Play» را راه‌اندازی کند و درخصوص هشدارهای «سپر ایمنی Play» اقدام کند. اگر کاربر نتواند این الزامات را برآورده کند، می‌توانید او را از کنش سرور مسدود کنید.