توضّح هذه الصفحة كيفية تفسير نتيجة التحقّق من السلامة التي تم عرضها والتعامل معها. سواء أجريت طلبًا عاديًا أو كلاسيكيًا من خلال واجهة برمجة التطبيقات، سيتم عرض نتيجة التحقّق من السلامة بالتنسيق نفسه وبمحتوى مشابه. تعرض نتيجة السلامة معلومات حول صحة الأجهزة والتطبيقات والحسابات. يمكن لخادم تطبيقك استخدام الحمولة الناتجة في بيان تم فك تشفيره والتحقّق منه لتحديد أفضل طريقة للمتابعة في إجراء أو طلب معيّن في تطبيقك.
تنسيق بيان السلامة الذي يتم عرضه
الحمولة هي 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 يتطابقان مع ما تم إرساله في الطلب الأصلي، كما هو موضّح في مقتطف الرمز التالي:
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. ... }
بالنسبة إلى طلبات البيانات من واجهة برمجة التطبيقات الكلاسيكية:
"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 يتطابقان مع ما تم إرساله في الطلب الأصلي، كما هو موضّح في مقتطف الرمز التالي:
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. ... }
حقل تفاصيل الحساب
يحتوي الحقل 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 هي القيمة المتوقّعة، كما هو موضّح في مقتطف الرمز البرمجي التالي:
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! }
حقل "سلامة التطبيق"
يحتوي الحقل 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- لم يتم تقييم سلامة التطبيق. ولم يتم استيفاء أحد المتطلّبات الضرورية، مثلاً أن يكون الجهاز غير موثوق بالقدر الكافي.
للتأكّد من أنّ الرمز المميز تم إنشاؤه بواسطة تطبيق أنشأته أنت، تحقَّق من أنّ سلامة التطبيق هي كما هو متوقّع، كما هو موضّح في مقتطف الرمز البرمجي التالي:
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! }
يمكنك أيضًا التحقّق يدويًا من اسم حزمة التطبيق وإصدار التطبيق وشهادات التطبيق.
حقل سلامة الجهاز
يمكن أن يحتوي الحقل deviceIntegrity على قيمة واحدة،
deviceRecognitionVerdict، تتضمّن تصنيفًا واحدًا أو أكثر يوضّح مدى قدرة الجهاز على فرض سلامة التطبيق. إذا لم يستوفِ الجهاز معايير أي من التصنيفات، سيحذف الحقل deviceIntegrity القيمة deviceRecognitionVerdict.
"deviceIntegrity": { // "MEETS_DEVICE_INTEGRITY" is one of several possible values. "deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"] }
بشكلٍ تلقائي، يمكن أن يتضمّن deviceRecognitionVerdict ما يلي:
MEETS_DEVICE_INTEGRITY- يعمل التطبيق على جهاز Android أصلي ومعتمَد. في الإصدار 13 من نظام التشغيل Android والإصدارات الأحدث، تتوفّر شهادة مستنِدة إلى الأجهزة تثبت أنّ برنامج إقلاع الجهاز مقفَل وأنّ نظام التشغيل Android الذي تم تحميله هو صورة معتمَدة من الشركة المصنّعة للجهاز.
- فارغ (قيمة فارغة)
- يعمل التطبيق على جهاز يتضمّن علامات تشير إلى تعرُّضه للهجوم (مثل اعتراض طلبات البيانات من واجهة برمجة التطبيقات) أو اختراق نظامه (مثل تزويده بإذن الوصول إلى الجذر)، أو لا يعمل التطبيق على جهاز فعلي (مثل المحاكي الذي لا يجتاز عمليات التأكّد من السلامة في Google Play).
للتأكّد من أنّ الرمز المميّز وارد من جهاز موثوق به، تحقَّق من أنّ
deviceRecognitionVerdict هو كما هو متوقّع، كما هو موضّح في مقتطف الرمز التالي:
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! }
إذا كنت تواجه مشاكل في استيفاء جهاز الاختبار لمتطلبات سلامة الجهاز، تأكَّد من تثبيت ذاكرة القراءة فقط (ROM) الأصلية (على سبيل المثال، من خلال إعادة ضبط الجهاز) ومن قفل برنامج الإقلاع. يمكنك أيضًا إنشاء اختبارات لواجهة Play Integrity API في Play Console.
تصنيفات الأجهزة الشَرطية
إذا كان تطبيقك سيتم إصداره على ألعاب Google Play على الكمبيوتر، يمكن أن يحتوي deviceRecognitionVerdict أيضًا على التصنيف التالي:
MEETS_VIRTUAL_INTEGRITY- يعمل التطبيق على محاكي Android متوافق مع خدمات Google Play. يجتاز المحاكي عمليات التأكّد من سلامة النظام ويستوفي متطلّبات التوافق الأساسية مع نظام Android.
معلومات الجهاز الاختيارية وميزة "تذكُّر الجهاز"
يمكنك الموافقة على تلقّي تصنيفات اختيارية للأجهزة كجزء من استراتيجية تنفيذ على عدة مستويات. في حال وافقت على تلقّي تصنيفات إضافية في بيان السلامة، يمكن أن يحتوي deviceRecognitionVerdict على التصنيفات الإضافية التالية:
MEETS_BASIC_INTEGRITY- يعمل التطبيق على جهاز يجتاز عمليات التحقق الأساسية من سلامة النظام.
يمكن قفل برنامج إقلاع الجهاز أو فتحه، ويمكن أن تكون حالة التشغيل
متحقَّقًا منها أو غير متحقَّق منها. قد لا يكون الجهاز معتمَدًا، وفي هذه الحالة، لا يمكن أن تقدّم Google أي ضمانات بشأن الأمان أو الخصوصية أو توافق التطبيقات. على الإصدار 13 من نظام التشغيل Android والإصدارات الأحدث، لا يتطلّب
MEETS_BASIC_INTEGRITYبيان السلامة سوى أن تقدّم Google جذر الثقة الخاص بشهادة التصديق. MEETS_STRONG_INTEGRITY- يعمل التطبيق على جهاز Android حقيقي ومعتمَد
يتضمّن آخر تحديث أمان.
- في الإصدار 13 من نظام التشغيل Android والإصدارات الأحدث، يتطلّب بيان السلامة
MEETS_STRONG_INTEGRITYMEETS_DEVICE_INTEGRITYوتحديثات الأمان خلال العام الماضي لجميع أقسام الجهاز، بما في ذلك تصحيح قسم نظام التشغيل Android وتصحيح قسم المورّد. - على نظام التشغيل Android 12 والإصدارات الأقدم، لا يتطلّب بيان السلامة
MEETS_STRONG_INTEGRITYسوى إثبات سلامة عملية التشغيل المستنِد إلى الأجهزة، كما لا يتطلّب أن يكون الجهاز قد تلقّى تحديث أمان حديثًا. لذلك، عند استخدامMEETS_STRONG_INTEGRITY، ننصحك أيضًا بأخذ إصدار حزمة تطوير البرامج (SDK) لنظام التشغيل Android في الاعتبار في الحقلdeviceAttributes.
- في الإصدار 13 من نظام التشغيل Android والإصدارات الأحدث، يتطلّب بيان السلامة
سيعرض جهاز واحد تصنيفات متعددة للأجهزة في حكم سلامة الجهاز إذا تم استيفاء كل معايير التصنيف.
سمات الجهاز
يمكنك أيضًا الموافقة على تلقّي سمات الجهاز التي تعرض إصدار حزمة تطوير البرامج (SDK) لنظام التشغيل Android الذي يعمل على الجهاز. يفيد إصدار حزمة تطوير البرامج (SDK) لنظام التشغيل Android في التمييز بين الأجهزة التي تعمل بالإصدار 13 من نظام التشغيل Android والإصدارات الأحدث والأجهزة التي تعمل بإصدارات أقدم من حزمة تطوير البرامج (SDK) لنظام التشغيل Android كجزء من استراتيجية التنفيذ المتدرّج. وقد يتم توسيع نطاقها في المستقبل لتشمل سمات أخرى للأجهزة.
قيمة إصدار حزمة SDK هي رقم إصدار حزمة SDK لنظام التشغيل Android المحدّد في
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 بين الأوضاع ويمكن أن تتضمّن إحدى القيم التالية:
| مستوى نشاط الجهاز الأخير | طلبات الرموز المميزة للسلامة العادية لواجهة برمجة التطبيقات على هذا الجهاز خلال آخر ساعة لكل تطبيق | طلبات الرمز المميز للسلامة في واجهة برمجة التطبيقات القديمة على هذا الجهاز خلال آخر ساعة لكل تطبيق |
|---|---|---|
LEVEL_1 (الأدنى) |
10 أو أقل | 5 أو أقل |
LEVEL_2 |
بين 11 و25 | بين 6 و10 |
LEVEL_3 |
بين 26 و50 | بين 11 و15 |
LEVEL_4 (الأعلى) |
أكثر من 50 | أكثر من 15 |
UNEVALUATED |
لم يتم تقييم ميزة "أحدث نشاط للجهاز". قد يحدث ذلك للأسباب التالية:
|
|
تذكُّر الجهاز (ميزة تجريبية)
يمكنك أيضًا تفعيل ميزة تذكُّر الجهاز، التي تتيح لك تخزين بعض البيانات المخصّصة لكل جهاز مع أجهزة معيّنة يمكنك استردادها بشكل موثوق به عند إعادة تثبيت تطبيقك لاحقًا على الجهاز نفسه. بعد طلب رمز مميّز للسلامة، يمكنك إجراء طلب منفصل من الخادم إلى الخادم من أجل تعديل قيم ميزة "تذكُّر الجهاز" لجهاز معيّن.
في حال تفعيل 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": {}
}
}
حقل تفاصيل البيئة
يمكنك أيضًا الموافقة على تلقّي إشارات إضافية عن البيئة. تتيح لك ميزة "احتمالية اختراق التطبيق" معرفة ما إذا كانت هناك تطبيقات أخرى قيد التشغيل يمكنها أخذ لقطات للشاشة أو عرض المحتوى على سطح الصفحة أو التحكم في الجهاز. يتيح لك بيان "Google Play للحماية" معرفة ما إذا كانت خدمة "Google Play للحماية" مفعَّلة على الجهاز وإذا كان قد تم اكتشاف برامج ضارة معروفة.
إذا وافقت على تلقّي بيان احتمالية اختراق التطبيق أو بيان Play للحماية في Google Play Console، سيتضمّن الردّ من واجهة برمجة التطبيقات الحقل 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فارغًا. وقد يحدث ذلك لعدة أسباب، بما فيها ما يلي:- الجهاز غير موثوق بالقدر الكافي
- شكل الجهاز ليس هاتفًا أو جهازًا لوحيًا أو جهازًا قابلاً للطي.
- لا يعمل الجهاز بالإصدار 6 من نظام التشغيل Android (المستوى 23 من واجهة برمجة التطبيقات) أو إصدار أحدث.
- لا يتعرّف 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"]
|
هناك تطبيقات على Google Play أو تطبيقات نظام قيد التشغيل تم تفعيل الأذونات فيها، ويمكن استخدامها لعرض الشاشة أو تسجيل المدخلات والمخرجات الأخرى. هناك أيضًا تطبيقات أخرى قيد التشغيل تم تفعيل الأذونات فيها، ويمكن استخدامها للتحكّم في الجهاز والتحكّم مباشرةً في المدخلات في تطبيقك. |
appAccessRiskVerdict: {}
|
لم يتم تقييم احتمالية اختراق التطبيق بسبب عدم استيفاء أحد المتطلّبات الضرورية. على سبيل المثال، لم يكن الجهاز موثوقًا بالقدر الكافي. |
استنادًا إلى مستوى الخطورة، يمكنك تحديد مجموعة بيانات السلامة المقبولة للمتابعة وبيانات السلامة التي تريد اتّخاذ إجراء بشأنها. يوضّح مقتطف الرمز التالي مثالاً على التحقّق من عدم وجود تطبيقات قيد التشغيل يمكنها أخذ لقطات للشاشة أو التحكّم في تطبيقك:
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! } }
معالجة بيانات احتمالية اختراق التطبيق
بناءً على مستوى المخاطر، يمكنك تحديد بيانات السلامة المتعلقة باحتمالية اختراق التطبيق التي تريد اتّخاذ إجراء بشأنها قبل السماح للمستخدم بإكمال طلب أو إجراء. تتوفّر طلبات اختيارية من Google Play يمكنك عرضها للمستخدم بعد التحقّق من بيان احتمالية اختراق التطبيق. يمكنك عرض CLOSE_UNKNOWN_ACCESS_RISK لطلب إغلاق التطبيقات غير المعروفة التي تتسبّب في ظهور بيان عن احتمالية اختراق التطبيق، أو يمكنك عرض CLOSE_ALL_ACCESS_RISK لطلب إغلاق جميع التطبيقات (المعروفة وغير المعروفة) التي تتسبّب في ظهور بيان عن احتمالية اختراق التطبيق.
بيان "Play للحماية"
بعد تفعيل هذه الميزة، سيتضمّن الحقل environmentDetails في حمولة Play Integrity API بيان "Google Play للحماية" على النحو التالي:
"environmentDetails": {
"playProtectVerdict": "NO_ISSUES"
}
يمكن أن تتضمّن playProtectVerdict إحدى القيم التالية:
NO_ISSUES- تكون ميزة "Play للحماية" مفعَّلة ولم ترصد أي مشاكل في التطبيقات على الجهاز.
NO_DATA- تكون خدمة "Play للحماية" مفعّلة ولكن لم يتم إجراء أي فحص حتى الآن. تمت إعادة ضبط الجهاز أو تطبيق "متجر Google Play" مؤخرًا.
POSSIBLE_RISK- خدمة "Play للحماية" غير مفعَّلة.
MEDIUM_RISK- تكون خدمة "Play للحماية" مفعّلة وقد رصدت تطبيقات مثبّتة على الجهاز قد تكون ضارّة.
HIGH_RISK- تكون خدمة "Play للحماية" مفعَّلة وقد رصدت تطبيقات خطيرة مثبّتة على الجهاز.
UNEVALUATEDلم يتم تقييم بيان حالة "Play للحماية".
وقد يحدث ذلك لعدة أسباب، بما فيها ما يلي:
- الجهاز غير موثوق بالقدر الكافي
- لا يملك حساب المستخدم ترخيصًا على Play.
إرشادات بشأن استخدام بيان "Google Play للحماية"
يمكن لخادم الخلفية في تطبيقك اتخاذ الإجراءات المناسبة بناءً على بيان السلامة ومستوى تحمّل تطبيقك للمخاطر. في ما يلي بعض الاقتراحات والإجراءات المحتملة التي يمكن للمستخدم اتّخاذها:
NO_ISSUES- تكون خدمة "Play للحماية" مفعَّلة ولم تعثر على أي مشاكل، لذا لا يلزم اتّخاذ أي إجراء من جانب المستخدم.
POSSIBLE_RISKوNO_DATA- عند تلقّي هذه النتائج، اطلب من المستخدم التأكّد من أنّ خدمة "Play للحماية" مفعّلة وأنّها أجرت عملية فحص. يجب ألا يظهر الرمز
NO_DATAإلا في حالات نادرة. MEDIUM_RISKوHIGH_RISK- استنادًا إلى مستوى تحمّلك للمخاطر، يمكنك أن تطلب من المستخدم تشغيل Play للحماية واتّخاذ إجراء بشأن تحذيرات Play للحماية. إذا لم يستوفِ المستخدم هذه المتطلبات، يمكنك حظره من تنفيذ إجراء الخادم.