קביעות התקינות

הדף הזה מתאר איך לפרש את התקינות שהוחזרה ולעבוד עםה בתוצאה. כששולחים בקשת API רגילה או קלאסית, התקינות היא מוחזרת בפורמט זהה עם תוכן דומה. התקינות הן מידע על התקינות של מכשירים, אפליקציות חשבונות. שרת האפליקציה יכול להשתמש במטען הייעודי (payload) שמתקבל בקובץ מפוענח, החלטה מאומתת כדי לקבוע מהי הדרך הטובה ביותר להמשיך בפעולה מסוימת, בקשה באפליקציה.

פורמט של קביעת התקינות שהוחזרה

המטען הייעודי (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 השמעת הרשומות.
UNEVALUATED
תקינות האפליקציה לא נבדקה. דרישה נחוצה שלא הוגשו, למשל שהמכשיר לא מספיק מהימן.

כדי לוודא שהאסימון נוצר על ידי אפליקציה שיצרת, עליך לאמת שתקינות האפליקציה תקינה, כפי שמוצג בקוד הבא snippet:

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!
}

אפשר גם לבדוק את השם של חבילת האפליקציה, את גרסת האפליקציה ואת אישורי האפליקציה במצב ה-GRU

שדה תקינות המכשיר

השדה deviceIntegrity יכול להכיל ערך אחד, deviceRecognitionVerdict, שכוללת תווית אחת או יותר שמייצגת את מידת היעילות של המכשיר יכול לאכוף את תקינות האפליקציה. אם מכשיר לא עומד בקריטריונים של תוויות, השדה deviceIntegrity ריק.

deviceIntegrity: {
  // "MEETS_DEVICE_INTEGRITY" is one of several possible values.
  deviceRecognitionVerdict: ["MEETS_DEVICE_INTEGRITY"]
}

כברירת מחדל, השדה deviceRecognitionVerdict יכול להכיל את הדברים הבאים:

MEETS_DEVICE_INTEGRITY
האפליקציה פועלת במכשיר מבוסס Android עם Google Play Services. המכשיר עובר את בדיקות התקינות של המערכת ועומד בדרישות דרישות התאימות של Android.
ריק (ערך ריק)
האפליקציה פועלת במכשיר שמופיעים בו סימנים מתקפה (למשל הוק (hooking) ל-API) או פריצה למערכת (למשל מעבר לרמה הבסיסית (root)), או האפליקציה לא פועלת במכשיר פיזי (כמו אמולטור לא לעבור את בדיקות התקינות של Google Play).

כדי לוודא שהאסימון הגיע ממכשיר מהימן, הערך של deviceRecognitionVerdict הוא כצפוי, כמו שמוצג בקוד הבא snippet:

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
האפליקציה פועלת במכשיר שעובר את השלבים הבסיסיים בדיקות תקינות של המערכת. יכול להיות שהמכשיר לא עומד בדרישות התאימות של Android של Google Play Services וייתכן שלא נאשר אותם. עבור לדוגמה, ייתכן שבמכשיר פועלת גרסה לא מזוהה של Android, אם מותקנת בשעון תוכנת אתחול לא נעולה, או אם תוכנת האתחול לא אושרה על ידי היצרן.
MEETS_STRONG_INTEGRITY
האפליקציה פועלת במכשיר מבוסס Android עם Google Play Services והאחריות לתקינות המערכת גבוהה, כמו הוכחה לתקינות ההפעלה שמגובה באמצעות חומרה. המכשיר עובר במערכת בדיקות תקינות ועמידה בדרישות התאימות של Android.

מכשיר יחיד יחזיר מספר תוויות של המכשיר בתקינות המכשיר ולקבוע אם כל אחד מהקריטריונים של התווית מתקיים.

פעילות במכשיר מהזמן האחרון

ניתן גם להביע הסכמה לפעילות האחרונה במכשיר, וכך לדעת איך פעמים רבות האפליקציה שלך ביקשה אסימון תקינות במכשיר ספציפי בשעה האחרונה. אתם יכולים להשתמש בפעילות האחרונה במכשיר כדי להגן על האפליקציה מפני מכשירים היפר-אקטיביים ולא צפויים שעשויים להוות אינדיקציה למתקפה פעילה. ניתן להחליט כמה לתת אמון בכל רמת פעילות במכשיר מהזמן האחרון על סמך האופן שבו הרבה פעמים אתם מצפים שהאפליקציה שלכם תותקן במכשיר רגיל יבקש מכם אסימון התקינות בכל שעה.

אם הבעת הסכמה לקבל recentDeviceActivity את השדה deviceIntegrity יהיו שני ערכים:

deviceIntegrity: {
  deviceRecognitionVerdict: ["MEETS_DEVICE_INTEGRITY"]
  recentDeviceActivity: {
    // "LEVEL_2" is one of several possible values.
    deviceActivityLevel: "LEVEL_2"
  }
}

ההגדרות של deviceActivityLevel משתנות בין מצבים, והן יכולות לכלול אחד מהערכים הבאים:

רמת הפעילות במכשיר מהזמן האחרון בקשות סטנדרטיות לאסימון תקינות של API במכשיר הזה בשעה האחרונה לכל אפליקציה בקשות לאסימון תקינות של API בגרסה הקלאסית של ה-API במכשיר הזה בשעה האחרונה לכל אפליקציה
LEVEL_1 (הנמוך ביותר) 10 או פחות 5 או פחות
LEVEL_2 בין 11 ל-25 6 עד 10
LEVEL_3 בין 26 ל-50 בין 11 ל-15
LEVEL_4 (הגבוה ביותר) יותר מ-50 יותר מ-15
UNEVALUATED לא בוצעה הערכה של הפעילות האחרונה במכשיר. זה יכול לקרות כי:
  • המכשיר לא מספיק מהימן.
  • הגרסה של האפליקציה שמותקנת במכשיר לא ידועה ל-Google הפעלה.
  • בעיות טכניות במכשיר.

שדה פרטי החשבון

השדה 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 הפעלה.
  • המשתמש לא מחובר ל-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 ב-Play Integrity API המטען הייעודי (Payload) יכיל קביעת סיכון הגישה של האפליקציה החדשה.

{
  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 שפועלים במכשיר.
EMPTY (ערך ריק)

לא מתבצעת הערכה של סיכון הגישה לאפליקציה אם לא עמדת בדרישה כלשהי. לחשבון במקרה הזה, השדה appAccessRiskVerdict ריק. מצב כזה יכול לקרות במקרים כמה סיבות, כולל הסיבות הבאות:

  • המכשיר לא מספיק מהימן.
  • גורם הצורה של המכשיר הוא לא טלפון, טאבלט או מכשיר מתקפל.
  • במכשיר לא פועלת מערכת Android בגרסה 6 (רמת API 23) ואילך.
  • הגרסה של האפליקציה שמותקנת במכשיר לא ידועה ל-Google Play.
  • הגרסה של חנות Google Play במכשיר מיושנת.
  • משחקים בלבד: לחשבון המשתמש אין רישיון Play למשחק.
  • נעשה שימוש בבקשה רגילה עם הפרמטר verdictOptOut.
  • נעשה שימוש בבקשה רגילה עם גרסת ספריית Play Integrity API שעדיין לא תומכת בסיכון הגישה לאפליקציה בבקשות רגילות.

האפשרות 'סיכון לגישה לאפליקציה' מחריגה באופן אוטומטי שירותי נגישות מאומתים עברו בדיקת נגישות משופרת ב-Google Play (הותקנו על ידי בכל חנות אפליקציות במכשיר). 'לא נכלל' היא שנגישות מאומתת שירותים שפועלים במכשיר לא יחזירו תיעוד, שליטה או שכבות-על של תגובה בקביעת סיכון הגישה לאפליקציה. כדי לבקש גרסה משופרת של Google הפעלה של בדיקת נגישות לאפליקציית הנגישות, פרסום האפליקציה ב-Google הפעלת המשחק כדי לוודא שהסימון 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 ב-Play Integrity API המטען הייעודי (Payload) יכיל ההחלטה של Play Protect:

environmentDetails: {
  playProtectVerdict: "NO_ISSUES"
}

playProtectVerdict יכול לקבל אחד מהערכים הבאים:

NO_ISSUES
Play Protect מופעל ולא נמצאו בעיות באפליקציה במכשיר.
NO_DATA
Play Protect מופעל אבל עדיין לא בוצעה סריקה. המכשיר או יכול להיות שאפליקציית חנות Play אופסה לאחרונה.
POSSIBLE_RISK
Play Protect מושבת.
MEDIUM_RISK
Play Protect מופעל ונמצאו בו אפליקציות שעלולות להזיק (PHA) במכשיר.
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 הגנה על אזהרות Play Protect ונקיטת פעולה בהתאם. אם המשתמש לא יכול למלא מידע (fufill) אפשר לחסום את הגישה שלו לפעולה בשרת.