توضّح هذه الصفحة كيفية تفسير الحكم الذي تم إرجاعه بشأن السلامة وكيفية التعامل معه. سواء أجريت طلب بيانات من واجهة برمجة التطبيقات عاديًا أو كلاسيكيًا، سيتم عرض بيان السلامة بالتنسيق نفسه وبمحتوى مشابه. تعرض بيانات السلامة معلومات عن صحة الأجهزة والتطبيقات والحسابات. يمكن لخادم تطبيقك استخدام الحمولة الناتجة في قرار تم فك تشفيره والتحقّق منه لتحديد أفضل طريقة للمتابعة في إجراء أو طلب معيّن في تطبيقك.
تنسيق بيان السلامة الذي يتم عرضه
الحمولة هي ملف JSON بنص عادي وتحتوي على إشارات السلامة بالإضافة إلى المعلومات التي يقدّمها المطوّر.
في ما يلي البنية العامة للحِزمة:
{ "requestDetails": { ... }, "appIntegrity": { ... }, "deviceIntegrity": { ... }, "accountDetails": { ... }, "environmentDetails": { ... } }
عليك أولاً التأكّد من أنّ القيم في الحقل 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. ... }
حقل سلامة التطبيق
يحتوي الحقل 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، تتضمّن تصنيفًا واحدًا أو أكثر يوضّح مدى قدرة الجهاز على فرض سلامة التطبيق. إذا لم يستوفِ الجهاز معايير أي من التصنيفات، سيتم حذف deviceRecognitionVerdict من الحقل deviceIntegrity.
"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 حقيقي ومعتمَد
يتضمّن آخر تحديث أمان.
- في نظام التشغيل Android 13 والإصدارات الأحدث، تتطلّب شهادة
MEETS_STRONG_INTEGRITYMEETS_DEVICE_INTEGRITYتحديثات الأمان خلال العام الماضي لجميع أقسام الجهاز، بما في ذلك تصحيح قسم نظام التشغيل Android وتصحيح قسم المورّد. - على نظام التشغيل Android 12 والإصدارات الأقدم، لا تتطلّب الاستجابة
MEETS_STRONG_INTEGRITYسوى تقديم دليل على سلامة عملية التشغيل من خلال مفتاح احتياطي، كما لا تتطلّب أن يكون الجهاز قد تلقّى تحديثًا أمنيًا حديثًا. لذلك، عند استخدامMEETS_STRONG_INTEGRITY، ننصحك أيضًا بأخذ إصدار حزمة تطوير البرامج (SDK) لنظام التشغيل Android في الاعتبار في الحقلdeviceAttributes.
- في نظام التشغيل Android 13 والإصدارات الأحدث، تتطلّب شهادة
سيعرض جهاز واحد تصنيفات متعددة للجهاز في نتيجة سلامة الجهاز إذا تم استيفاء كل معايير التصنيف.
سمات الجهاز
يمكنك أيضًا الموافقة على تلقّي سمات الجهاز التي توضّح إصدار حزمة تطوير البرامج (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": {}
}
}
حقل تفاصيل الحساب
يحتوي الحقل 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! }
حقل تفاصيل البيئة
يمكنك أيضًا الموافقة على تلقّي إشارات إضافية عن البيئة. تتيح لك ميزة "احتمالية اختراق التطبيق" معرفة ما إذا كانت هناك تطبيقات أخرى قيد التشغيل يمكنها أخذ لقطات للشاشة أو عرض المحتوى على سطح الصفحة أو التحكم في الجهاز. يتيح لك بيان "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"]
|
هناك تطبيقات على 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 للحماية" مفعّلة ولكن لم يتم إجراء أي فحص حتى الآن. ربما تمت إعادة ضبط الجهاز أو تطبيق "متجر 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 للحماية". إذا لم يستوفِ المستخدم هذه المتطلبات، يمكنك حظره من تنفيذ إجراء الخادم.