בדף הזה מוסבר איך לפרש את תוצאת הבדיקה של תקינות הנתונים שמוחזרת ואיך לעבוד איתה. לא משנה אם שולחים בקשת API רגילה או בקשת API דרך Classic API, קביעת התקינות מוחזרת באותו פורמט עם תוכן דומה. התוצאה של בדיקת התקינות מספקת מידע על התוקף של מכשירים, אפליקציות וחשבונות. השרת של האפליקציה יכול להשתמש במטען הייעודי (payload) שמתקבל בתוצאה מפוענחת ומאומתת, כדי לקבוע מהי הדרך הטובה ביותר להמשיך בפעולה או בבקשה מסוימת באפליקציה.
פורמט קביעת התקינות שמוחזר
המטען הייעודי הוא JSON בטקסט פשוט, והוא מכיל אותות יושרה לצד מידע שהמפתח סיפק.
המבנה הכללי של המטען הייעודי (payload) הוא כזה:
{ "requestDetails": { ... }, "appIntegrity": { ... }, "deviceIntegrity": { ... }, "accountDetails": { ... }, "environmentDetails": { ... } }
לפני שבודקים כל פסיקה לגבי תקינות, צריך לוודא שהערכים בשדה requestDetails זהים לערכים בבקשה המקורית. בקטעים הבאים מפורט כל שדה.
שדה פרטי הבקשה
השדה requestDetails מכיל מידע על הבקשה, כולל מידע שהמפתח סיפק בשדה requestHash לבקשות רגילות ובשדה nonce לבקשות קלאסיות.
לגבי בקשות API רגילות:
"requestDetails": { // Application package name this attestation was requested for. // Note that this field might be spoofed in the middle of the request. "requestPackageName": "com.package.name", // Request hash provided by the developer. "requestHash": "aGVsbG8gd29scmQgdGhlcmU", // The timestamp in milliseconds when the integrity token // was requested. "timestampMillis": "1675655009345" }
הערכים האלה צריכים להיות זהים לאלה של הבקשה המקורית. לכן, צריך לוודא שהחלק requestDetails במטען הייעודי (payload) בפורמט 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. ... }
בבקשות API קלאסיות:
"requestDetails": { // Application package name this attestation was requested for. // Note that this field might be spoofed in the middle of the // request. "requestPackageName": "com.package.name", // base64-encoded URL-safe no-wrap nonce provided by the developer. "nonce": "aGVsbG8gd29scmQgdGhlcmU", // The timestamp in milliseconds when the request was made // (computed on the server). "timestampMillis": "1617893780" }
הערכים האלה צריכים להיות זהים לאלה של הבקשה המקורית. לכן, צריך לוודא שהחלק requestDetails במטען הייעודי (payload) בפורמט JSON תואם למה שנשלח בבקשה המקורית, כפי שמוצג בקטע הקוד הבא:requestPackageNamenonce
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! }
אפשר גם לבדוק באופן ידני את שם חבילת האפליקציה (APK), את גרסת האפליקציה ואת האישורים של האפליקציה.
שדה תקינות המכשיר
השדה 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 hooking) או לפריצה למערכת (למשל, רוט), או שהאפליקציה לא פועלת במכשיר פיזי (למשל, אמולטור שלא עובר את בדיקות היושרה של 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 Games למחשב, התווית deviceRecognitionVerdict יכולה לכלול גם את התווית הבאה:
MEETS_VIRTUAL_INTEGRITY- האפליקציה פועלת באמולטור מבוסס-Android עם Google Play Services. האמולטור עובר את בדיקות התקינות של המערכת ועומד בדרישות התאימות הבסיסיות של Android.
מידע אופציונלי על המכשיר ושחזור ערכים לפי מכשיר
אתם יכולים להביע הסכמה לקבלת תוויות מכשיר אופציונליות כחלק מאסטרטגיית אכיפה מדורגת. אם תביעו הסכמה לקבלת תוויות נוספות בקביעת התקינות, deviceRecognitionVerdict יכול להכיל את התוויות הנוספות הבאות:
MEETS_BASIC_INTEGRITY- האפליקציה פועלת במכשיר שעובר את הבדיקות הבסיסיות של תקינות המערכת.
תוכנת האתחול של המכשיר יכולה להיות נעולה או לא נעולה, ומצב ההפעלה יכול להיות מאומת או לא מאומת. יכול להיות שהמכשיר לא קיבל אישור, ובמקרה כזה Google לא יכולה לספק הבטחות לגבי אבטחה, פרטיות או תאימות לאפליקציות. ב-Android מגרסה 13 ואילך,
MEETS_BASIC_INTEGRITYכדי לקבל את התוצאה, צריך רק ש-Google תספק את שורש האמון של האימות. MEETS_STRONG_INTEGRITY- האפליקציה פועלת במכשיר Android מקורי ותואם עם עדכון אבטחה מהזמן האחרון.
- ב-Android 13 ומעלה, כדי לקבל את התוצאה
MEETS_STRONG_INTEGRITY, צריךMEETS_STRONG_INTEGRITYלהתקין עדכוני אבטחה בשנה האחרונה בכל המחיצות של המכשיר, כולל תיקון של מחיצת Android OS ותיקון של מחיצת הספק.MEETS_DEVICE_INTEGRITY - ב-Android 12 ובגרסאות קודמות, כדי לקבל את תוצאת הבדיקה
MEETS_STRONG_INTEGRITYנדרש רק אימות מבוסס-חומרה של תקינות ההפעלה, ולא נדרש שהמכשיר יכלול עדכון אבטחה מהזמן האחרון. לכן, כשמשתמשים ב-MEETS_STRONG_INTEGRITY, מומלץ לקחת בחשבון גם את גרסת Android SDK בשדהdeviceAttributes.
- ב-Android 13 ומעלה, כדי לקבל את התוצאה
מכשיר יחיד יחזיר כמה תוויות של מכשירים בתוצאת בדיקת תקינות המכשיר אם כל הקריטריונים של התווית מתקיימים.
מאפייני המכשיר
אפשר גם להביע הסכמה לשיתוף מאפייני המכשיר, שכוללים את גרסת Android SDK של מערכת ההפעלה Android שפועלת במכשיר. גרסת Android SDK שימושית להבחנה בין מכשירים עם Android 13 ומעלה לבין מכשירים עם גרסאות Android SDK נמוכות יותר, כחלק מאסטרטגיית אכיפה מדורגת. יכול להיות שבעתיד נרחיב את התכונה הזו ונוסיף לה מאפיינים נוספים של מכשירים.
הערך של גרסת ה-SDK הוא מספר גרסת Android SDK שמוגדר ב-Build.VERSION_CODES. אם לא עמדתם בדרישה כלשהי, המערכת לא תבדוק את גרסת ה-SDK. במקרה הזה, השדה sdkVersion לא מוגדר, ולכן השדה deviceAttributes ריק.
הסיבות האפשריות לכך הן:
- המכשיר לא מספיק מהימן.
- היו בעיות טכניות במכשיר.
אם תבחרו להפעיל את האפשרות לקבלת deviceAttributes, בשדה deviceIntegrity יופיע השדה הנוסף הבא:
"deviceIntegrity": { "deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"], "deviceAttributes": { // 33 is one possible value, which represents Android 13 (Tiramisu). "sdkVersion": 33 } }
אם גרסת ה-SDK לא נבדקת, השדה deviceAttributes יוגדר כך:
"deviceIntegrity": { "deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"], "deviceAttributes": {} // sdkVersion field is not set. }
פעילות במכשיר מהזמן האחרון
אתם יכולים גם להביע הסכמה לשימוש באות 'פעילות במכשיר מהזמן האחרון', שמציין כמה פעמים האפליקציה שלכם ביקשה טוקן תקינות במכשיר ספציפי בשעה האחרונה. אתם יכולים להשתמש בפעילות במכשיר מהזמן האחרון כדי להגן על האפליקציה מפני מכשירים לא צפויים והיפראקטיביים, שיכולים להעיד על מתקפה פעילה. אתם יכולים להחליט עד כמה אתם סומכים על כל רמה של פעילות במכשיר מהזמן האחרון, על סמך מספר הפעמים שאתם מצפים שהאפליקציה שלכם תבקש טוקן תקינות בכל שעה במכשיר טיפוסי.
אם תביעו הסכמה לקבלת recentDeviceActivity, בשדה deviceIntegrity יהיו שני ערכים:
"deviceIntegrity": { "deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"], "recentDeviceActivity": { // "LEVEL_2" is one of several possible values. "deviceActivityLevel": "LEVEL_2" } }
ההגדרות של deviceActivityLevel שונות בין המצבים, והערך יכול להיות אחד מהערכים הבאים:
| רמת הפעילות במכשיר מהזמן האחרון | בקשות לטוקן תקינות של Standard API במכשיר הזה בשעה האחרונה לכל אפליקציה | בקשות קלאסיות לטוקן תקינות במכשיר הזה בשעה האחרונה לכל אפליקציה |
|---|---|---|
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: תאריכי כתיבת הביטים ב-UTC, ברמת דיוק של שנה וחודש. תאריך הכתיבה של ביט ההחזרה יתעדכן בכל פעם שהביט מוגדר לערךtrue, והוא יוסר כשהביט מוגדר לערךfalse.
אם פרטי שחזור ערכים לפי מכשיר לא זמינים, הערך של שחזור ערכים לפי מכשיר יהיה ריק:
"deviceIntegrity": {
"deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"],
"deviceRecall": {
"values": {},
"writeDates": {}
}
}
השדה של פרטי החשבון
השדה accountDetails מכיל ערך יחיד, appLicensingVerdict, שמייצג את סטטוס הרישיון של האפליקציה ב-Google Play עבור חשבון המשתמש שמחובר למכשיר. אם לחשבון המשתמש יש רישיון לשימוש באפליקציה ב-Play,
זה אומר שהמשתמש הוריד או קנה אותה מ-Google Play.
"accountDetails": { // This field can be LICENSED, UNLICENSED, or UNEVALUATED. "appLicensingVerdict": "LICENSED" }
הערך appLicensingVerdict יכול להיות אחד מהערכים הבאים:
LICENSED- למשתמש יש הרשאה לאפליקציה. במילים אחרות, המשתמש התקין או עדכן את האפליקציה שלך מ-Google Play במכשיר שלו.
UNLICENSED- למשתמש אין הרשאה לאפליקציה. זה קורה למשל כשהמשתמש מתקין את האפליקציה בשיטה חלופית, או לא מתקין אותה דרך Google Play. כדי לפתור את הבעיה, אפשר להציג למשתמשים את תיבת הדו-שיח GET_LICENSED.
UNEVALUATEDלא בוצע ניתוח של פרטי הרישיון כי לא עמדת בדרישה נדרשת.
יכולות להיות לכך כמה סיבות, כולל:
- המכשיר לא מספיק מהימן.
- גרסת האפליקציה שמותקנת במכשיר לא ידועה ל-Google Play.
- המשתמש לא מחובר ל-Google Play.
כדי לוודא שלמשתמש יש הרשאה להשתמש באפליקציה, צריך לוודא שהערך של appLicensingVerdict הוא כמו שציפיתם, כפי שמוצג בקטע הקוד הבא:
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! }
שדה פרטי הסביבה
אפשר גם להפעיל אותות נוספים לגבי הסביבה. האות 'סיכון לגישה לאפליקציה' מאפשר לאפליקציה לדעת אם יש אפליקציות פועלות אחרות שיכולות לצלם את המסך, להציג שכבות-על או לשלוט במכשיר. הסטטוס של Play Protect מציין אם Google Play Protect מופעל במכשיר ואם הוא זיהה תוכנות זדוניות מוכרות.
אם בחרתם להשתמש בתוצאת הסיכון לגישה לאפליקציה או בתוצאת Play Protect ב-Google Play Console, התגובה של ה-API תכלול את השדה environmentDetails. השדה environmentDetails יכול להכיל שני ערכים, appAccessRiskVerdict ו-playProtectVerdict.
קביעת סיכון הגישה לאפליקציה
אחרי ההפעלה, השדה environmentDetails במטען הייעודי (payload) של 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 (רמת API 23) ואילך.
- גרסת האפליקציה שמותקנת במכשיר לא מוכרת ל-Google Play.
- הגרסה של חנות Google Play במכשיר לא עדכנית.
- לחשבון המשתמש אין רישיון ל-Play.
- נעשה שימוש בבקשה רגילה עם הפרמטר
verdictOptOut. - נעשה שימוש בבקשה רגילה עם גרסה של ספריית Play Integrity API שלא תומכת עדיין בסיכון לגישה לאפליקציה בבקשות רגילות.
הסיכון לגישה לאפליקציה מחריג באופן אוטומטי שירותי נגישות מאומתים שעברו בדיקת נגישות משופרת ב-Google Play (שהותקנו על ידי חנות אפליקציות כלשהי במכשיר). המשמעות של 'לא נכלל' היא ששירותי נגישות מאומתים שפועלים במכשיר לא יחזירו תגובה של לכידה, שליטה או שכבות-על בפסק הדין של סיכון הגישה לאפליקציה. כדי לבקש בדיקת נגישות משופרת של Google Play לאפליקציית הנגישות שלכם, אתם צריכים לפרסם אותה ב-Google Play ולוודא שהערך של הדגל isAccessibilityTool במניפסט של האפליקציה מוגדר כ-true, או לשלוח בקשה לבדיקה.
דוגמאות לקביעות סיכון הגישה לאפליקציה
בטבלה הבאה מוצגות כמה דוגמאות לתוצאות של סיכון גישה לאפליקציה והמשמעות שלהן (הטבלה לא כוללת את כל התוצאות האפשריות):
| דוגמה לתגובה של קביעת סיכון הגישה לאפליקציה | פירוש |
|---|---|
appsDetected:["KNOWN_INSTALLED"]
|
במכשיר מותקנות רק אפליקציות שמזוהות על ידי Google Play או שנטענו מראש במחיצת המערכת על ידי יצרן המכשיר. לא מופעלות אפליקציות שיובילו לתוצאות של לכידה, שליטה או שכבות-על. |
appsDetected:["KNOWN_INSTALLED","UNKNOWN_INSTALLED","UNKNOWN_CAPTURING"]
|
יש אפליקציות שהותקנו דרך Google Play או שהוטענו מראש במחיצת המערכת על ידי יצרן המכשיר. יש אפליקציות אחרות שפועלות וההרשאות שלהן מופעלות, ואפשר להשתמש בהן כדי לראות את המסך או לצלם קלט ופלט אחרים. |
appsDetected:["KNOWN_INSTALLED","KNOWN_CAPTURING","UNKNOWN_INSTALLED","UNKNOWN_CONTROLLING"]
|
יש אפליקציות של Play או אפליקציות מערכת שפועלות עם הרשאות מופעלות, שאפשר להשתמש בהן כדי להציג את המסך או לצלם קלט ופלט אחרים. יש גם אפליקציות אחרות שפועלות עם הרשאות מופעלות, שיכולות לשמש לשליטה במכשיר ולשליטה ישירה בקלט באפליקציה שלך. |
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 Protect
אחרי ההפעלה, השדה environmentDetails במטען הייעודי (payload) של Play Integrity API יכיל את קביעת התקינות של Play Protect:
"environmentDetails": {
"playProtectVerdict": "NO_ISSUES"
}
הערך playProtectVerdict יכול להיות אחד מהערכים הבאים:
NO_ISSUES- השירות Play Protect מופעל ולא נמצאו בעיות באפליקציות במכשיר.
NO_DATA- שירותי Play Protect מופעלים, אבל עדיין לא בוצעה סריקה. יכול להיות שהמכשיר או אפליקציית חנות Play אופסו לאחרונה.
POSSIBLE_RISK- שירות Play Protect מושבת.
MEDIUM_RISK- השירות Play Protect מופעל ומצא אפליקציות שעלולות להזיק שמותקנות במכשיר.
HIGH_RISK
- Play Protect מופעל ומצא אפליקציות מסוכנות שמותקנות במכשיר.
UNEVALUATEDקביעת הסטטוס של Play Protect לא הוערכה.
יכולות להיות לכך כמה סיבות, כולל:
- המכשיר לא מספיק מהימן.
- לחשבון המשתמש אין רישיון ל-Play.
הנחיות לשימוש בתוצאת הבדיקה של Play Protect
מערכת השרת העורפי של האפליקציה יכולה להחליט איך לפעול בהתאם לתוצאה, על סמך רמת הסיכון שאתם מוכנים לקחת. הנה כמה הצעות ופעולות אפשריות שהמשתמשים יכולים לבצע:
NO_ISSUES- ההגנה של Play Protect מופעלת ולא נמצאו בעיות, לכן לא נדרשת פעולה מצד המשתמש.
POSSIBLE_RISKוגםNO_DATA- כשמקבלים את התוצאות האלה, צריך לבקש מהמשתמש לבדוק ש-Play Protect מופעל ושהוא ביצע סריקה.
NO_DATAאמור להופיע רק במקרים נדירים. MEDIUM_RISKוגםHIGH_RISK- בהתאם לסף הסיכון שלכם, אתם יכולים לבקש מהמשתמש להפעיל את Play Protect ולפעול לפי האזהרות של Play Protect. אם המשתמש לא עומד בדרישות האלה, אפשר לחסום אותו מביצוע פעולות בשרת.