בדף הזה מוסבר איך לפרש את פסק הדין שמוחזר לגבי תקינות המערכת ואיך לעבוד איתו. לא משנה אם שולחים בקשת 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 תואם לערכים של 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
לא יכלול את 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) או לפריצה למערכת (למשל, rooting), או שהאפליקציה לא פועלת במכשיר פיזי (למשל, אמולטור שלא עובר את בדיקות התקינות של 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_DEVICE_INTEGRITY
עדכוני אבטחה בשנה האחרונה לכל המחיצות במכשיר, כולל תיקון של מחיצת מערכת ההפעלה Android ותיקון של מחיצת הספק. - ב-Android 12 ובגרסאות קודמות, כדי לקבל את קביעת התקינות
MEETS_STRONG_INTEGRITY
נדרש רק אימות מבוסס חומרה של תקינות ההפעלה, ולא נדרש שהמכשיר יכלול עדכון אבטחה מהזמן האחרון. לכן, כשמשתמשים ב-MEETS_STRONG_INTEGRITY
, מומלץ לקחת בחשבון גם את גרסת Android SDK בשדהdeviceAttributes
.
- ב-Android 13 ומעלה, כדי לקבל את התוצאה
אם מכשיר אחד עומד בקריטריונים של כמה תוויות, הוא יחזיר כמה תוויות מכשיר בתוצאת בדיקת תקינות המכשיר.
מאפייני המכשיר
אפשר גם להביע הסכמה לשיתוף מאפייני המכשיר, שכוללים את גרסת Android SDK של מערכת ההפעלה Android שפועלת במכשיר. יכול להיות שבעתיד נרחיב את התכונה הזו ונוסיף לה מאפיינים נוספים של מכשירים.
הערך של גרסת ה-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
שונות בין המצבים, והערך יכול להיות אחד מהערכים הבאים:
רמת הפעילות במכשיר מהזמן האחרון | בקשות רגילות לטוקן תקינות של 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. אם המשתמש לא עומד בדרישות האלה, אפשר לחסום אותו מביצוע פעולות בשרת.