توضّح هذه الصفحة كيفية تفسير نتيجة INTEGRITY المعروضة وكيفية التعامل معها. سواء أكنت تُجري طلبًا عاديًا أو كلاسيكيًا لواجهة برمجة التطبيقات، يتم عرض نتيجة السلامة بالتنسيق نفسه وبمحتوى مشابه. يعرض بيان السلامة معلومات عن صلاحية الأجهزة والتطبيقات والحسابات. يمكن لخادم تطبيقك استخدام الحمولة الناتجة في بيان سلامة مفعَّل التشفير ومُثبَّت صحته لتحديد أفضل طريقة لمتابعة إجراء معيّن أو طلب معيّن في تطبيقك.
تنسيق بيان السلامة الذي يتم إرجاعه
الحمولة هي نص 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
، تحتوي على تصنيف واحد أو أكثر يمثّل مدى قدرة
الجهاز على فرض سلامة التطبيق. إذا لم يستوفِ الجهاز معايير أيٍّ من
التصنيفات، يكون الحقل deviceIntegrity
فارغًا.
deviceIntegrity: { // "MEETS_DEVICE_INTEGRITY" is one of several possible values. deviceRecognitionVerdict: ["MEETS_DEVICE_INTEGRITY"] }
يمكن أن يحتوي العنصر deviceRecognitionVerdict
تلقائيًا على ما يلي:
MEETS_DEVICE_INTEGRITY
- يعمل التطبيق على جهاز Android أصلي معتمَد من "Play للحماية". في الإصدار 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
- يعمل التطبيق على أي جهاز يجتاز عمليات التحقق الأساسية من سلامة النظام.
يمكن قفل برنامج إقلاع الجهاز أو فتح قفله، ويمكن أن تكون حالة التشغيل
متحقَّقة أو غير متحقَّقة. قد لا يكون الجهاز معتمدًا من "Play للحماية"، وبالتالي
لا يمكن لشركة Google تقديم أي ضمانات بشأن الأمان أو الخصوصية أو توافق التطبيقات. في الإصدار 13 من نظام التشغيل Android والإصدارات الأحدث، لا يتطلّب بيان
MEETS_BASIC_INTEGRITY
سوى أن تقدّم Google جذر الثقة لشهادة الاعتماد. MEETS_STRONG_INTEGRITY
- يعمل التطبيق على جهاز Android أصلي معتمَد من "Play للحماية"
تم تثبيت تحديث أمان عليه مؤخرًا.
- على نظام التشغيل Android 13 والإصدارات الأحدث، يتطلّب بيان
MEETS_STRONG_INTEGRITY
MEETS_DEVICE_INTEGRITY
وتحديثات الأمان في العام الماضي لجميع أقسام الجهاز، بما في ذلك رمز تصحيح لقسم نظام التشغيل Android ورمز تصحيح لقسم المورّد. - في نظام التشغيل Android 12 والإصدارات الأقدم، لا يتطلب التقييم
MEETS_STRONG_INTEGRITY
سوى إثبات سلامة عملية التمهيد باستخدام جهاز ولا يتطلب أن يكون الجهاز قد تلقّى تحديث أمان حديثًا. لذلك، عند استخدامMEETS_STRONG_INTEGRITY
، ننصحك أيضًا بمراعاة إصدار حزمة تطوير البرامج (SDK) لنظام التشغيل Android في حقلdeviceAttributes
.
- على نظام التشغيل Android 13 والإصدارات الأحدث، يتطلّب بيان
سيعرض جهاز واحد تصنيفات أجهزة متعددة في نتيجة سلامة الجهاز في حال استيفاء كل معايير التصنيف.
سمات الجهاز
يمكنك أيضًا تفعيل سمات الجهاز التي تُعلم إصدار حزمة تطوير البرامج (SDK) لنظام التشغيل Android بنظام التشغيل 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
على 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 أو تطبيقات نظام قيد التشغيل تم تفعيل أذونات لها يمكن استخدامها لعرض الشاشة أو تسجيل مدخلات ومخرجات أخرى. هناك أيضًا تطبيقات أخرى قيد التشغيل تم تفعيل أذونات لها يمكن استخدامها للتحكّم في الجهاز والتحكّم مباشرةً في الإدخالات في تطبيقك. |
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 لطلب إغلاق جميع التطبيقات (المعروفة وغير المعروفة) التي تتسبب في بيان احتمالية اختراق التطبيق.
بيان "Google 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
لم يتم تقييم قرار "Google Play للحماية".
وقد يحدث ذلك لعدة أسباب، بما فيها ما يلي:
- الجهاز غير موثوق بالقدر الكافي
- الألعاب فقط: لا يملك حساب المستخدم ترخيصًا على Play للّعبة.
إرشادات حول استخدام بيان "Google Play للحماية"
يمكن لخادم الخلفية في تطبيقك اتخاذ الإجراءات المناسبة بناءً على بيان السلامة وبناءً على مستوى تحمّل تطبيقك للمخاطر. في ما يلي بعض الاقتراحات وإجراءات المستخدمين المحتمَلة:
NO_ISSUES
- تم تفعيل خدمة "Play للحماية" ولم يتم العثور على أي مشاكل، لذا ليس على المستخدم اتّخاذ أي إجراء.
POSSIBLE_RISK
وNO_DATA
- عند تلقّي هذه الأحكام، اطلب من المستخدم التحقّق من تفعيل خدمة "Play للحماية"
وإجراء فحص. من المفترض ألا يظهر الرمز
NO_DATA
إلا في حالات نادرة. MEDIUM_RISK
وHIGH_RISK
- استنادًا إلى مستوى المخاطر المقبولة لديك، يمكنك أن تطلب من المستخدم تشغيل تطبيق "Play الحماية" واتّخاذ إجراء بشأن تحذيرات "Play للحماية". إذا لم يتمكّن المستخدم من استيفاء هذه المتطلبات، يمكنك حظره من إجراء الخادم.