שליחת בקשה קלאסית ל-API

אם אתם מתכננים לשלוח רק בקשות API רגילות, שמתאימות לרוב המפתחים, אתם יכולים לדלג אל קביעות התקינות. בדף הזה מוסבר איך לשלוח בקשות API קלאסיות לקבלת קביעות לגבי תקינות, שנתמכות ב-Android מגרסה 4.4 (רמת API‏ 19) ואילך.

שיקולים

השוואה בין בקשות רגילות לבקשות קלאסיות

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

בטבלה הבאה מפורטים ההבדלים העיקריים בין שני סוגי הבקשות:

בקשת API רגילה בקשת API קלאסית
דרישות מוקדמות
גרסת Android SDK מינימלית נדרשת ‫Android מגרסה 5.0 (רמת API‏ 21) ואילך ‫Android 4.4 (API ברמה 19) ואילך
הדרישות של Google Play חנות Google Play ו-Google Play Services חנות Google Play ו-Google Play Services
פרטי השילוב
נדרש חימום של ה-API ✔️ (כמה שניות)
זמן אחזור טיפוסי של בקשות כמה מאות אלפיות שנייה כמה שניות
תדירות פוטנציאלית של בקשות תדירות גבוהה (בדיקה לפי דרישה של כל פעולה או בקשה) לא תדיר (בדיקה חד-פעמית של פעולות עם הערך הגבוה ביותר או של בקשות רגישות במיוחד)
חסימות זמניות רוב החימומים נמשכים פחות מ-10 שניות, אבל הם כוללים קריאה לשרת, ולכן מומלץ להגדיר פסק זמן ארוך (למשל, דקה אחת). בקשות לפסיקה מתבצעות בצד הלקוח רוב הבקשות נמשכות פחות מ-10 שניות, אבל הן כוללות קריאה לשרת, ולכן מומלץ להגדיר פסק זמן ארוך (למשל, דקה אחת)
טוקן של קביעת תקינות
כולל פרטים על המכשיר, האפליקציה והחשבון ✔️ ✔️
שמירת טוקנים במטמון מטמון במכשיר שמוגן על ידי Google Play לא מומלץ
פענוח ואימות של טוקן דרך שרת Google Play ✔️ ✔️
זמן האחזור האופייני של בקשות פענוח משרת לשרת עשרות אלפיות שנייה עם זמינות של 99.9% עשרות אלפיות שנייה עם זמינות של 99.9%
פענוח ואימות של טוקן באופן מקומי בסביבת שרת מאובטחת ✔️
פענוח ואימות של טוקן בצד הלקוח
עדכניות של קביעת התקינות חלק מהשמירה במטמון והרענון מתבצעים אוטומטית על ידי Google Play כל ההחלטות מחושבות מחדש בכל בקשה
מגבלות
בקשות לכל אפליקציה ביום 10,000 כברירת מחדל (אפשר לבקש להגדיל את המכסה) 10,000 כברירת מחדל (אפשר לבקש להגדיל את המכסה)
בקשות לכל מופע של אפליקציה בדקה חימום: 5 לדקה
אסימוני יושרה: אין מגבלה ציבורית*
טוקנים שלמות: 5 לדקה
הגנה
צמצום הסיכון לפגיעה ולמתקפות דומות שימוש בשדה requestHash שימוש בשדה nonce עם שיוך תוכן על סמך נתוני הבקשה
צמצום הסיכון להתקפות חוזרות ולהתקפות דומות הפחתת הסיכון באופן אוטומטי על ידי Google Play שימוש בשדה nonce עם לוגיקה בצד השרת

* כל הבקשות, כולל אלה ללא מגבלות ציבוריות, כפופות למגבלות הגנה לא ציבוריות בערכים גבוהים

יצירת בקשות קלאסיות בתדירות נמוכה

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

הימנעות משמירת פסקי דין במטמון

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

שימוש בשדה nonce להגנה על בקשות קלאסיות

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

ניסיון חוזר של בקשות דרך Classic API עם השהיה מעריכית לפני ניסיון חוזר (exponential backoff)

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

סקירה כללית

איור 1. דיאגרמת רצף שמציגה את העיצוב הכללי של Play Integrity API.

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

  1. הקצה העורפי בצד השרת של האפליקציה יוצר ושולח ערך ייחודי ללוגיקה בצד הלקוח. השלבים הבאים מתייחסים ללוגיקה הזו כאל 'האפליקציה'.
  2. האפליקציה יוצרת את nonce מהערך הייחודי ומהתוכן של הפעולה בעלת הערך הגבוה. לאחר מכן, המודול קורא ל-Play Integrity API ומעביר את הערך nonce.
  3. האפליקציה מקבלת קביעה חתומה ומוצפנת מ-Play Integrity API.
  4. האפליקציה מעבירה את פסק הדין החתום והמוצפן לשרת העורפי של האפליקציה.
  5. הקצה העורפי של האפליקציה שולח את התוצאה לשרת של Google Play. השרת של Google Play מפענח ומאמת את התוצאה ומחזיר את התוצאות לשרת העורפי של האפליקציה.
  6. הקצה העורפי של האפליקציה קובע איך להמשיך, על סמך האותות שכלולים במטען הייעודי (payload) של האסימון.
  7. הקצה העורפי של האפליקציה שולח את תוצאות ההחלטה לאפליקציה.

יצירת מספר חד-פעמי

כשמגנים על פעולה באפליקציה באמצעות Play Integrity API, אפשר להשתמש בשדה nonce כדי לצמצם את הסיכון לסוגים מסוימים של התקפות, כמו התקפות שיבוש מסוג 'אדם באמצע' (PITM) והתקפות שידור חוזר. ‫Play Integrity API מחזיר את הערך שהגדרתם בשדה הזה בתוך תגובת השלמות החתומה.

הערך שמוגדר בשדה nonce צריך להיות בפורמט הנכון:

  • String
  • בטוח לשימוש בכתובת URL
  • מקודד כ-Base64 ללא גלישת שורות
  • לפחות 16 תווים
  • עד 500 תווים

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

הוספת גיבוב של הבקשה כדי להגן מפני שינוי לא מורשה

אפשר להשתמש בפרמטר nonce בבקשת API קלאסית באופן דומה לפרמטר requestHash בבקשת API רגילה, כדי להגן על תוכן הבקשה מפני שינויים לא מורשים.

כשמבקשים קביעת תקינות:

  1. מחשבים תקציר של כל הפרמטרים הקריטיים של הבקשה (לדוגמה, SHA256 של סדרת בקשות יציבה) מפעולת המשתמש או מבקשת השרת שמתרחשת.
  2. משתמשים ב-setNonce כדי להגדיר את השדה nonce לערך של הגיבוב המחושב.

כשמקבלים קביעת תקינות:

  1. מפענחים ומאמתים את טוקן השלמות, ומקבלים את הגיבוב מהשדה nonce.
  2. מחשבים את התקציר של הבקשה באותו אופן שבו הוא מחושב באפליקציה (למשל, SHA256 של סריאליזציה יציבה של בקשה).
  3. משווים בין התקצירים בצד האפליקציה ובצד השרת. אם הם לא תואמים, הבקשה לא מהימנה.

הוספת ערכים ייחודיים להגנה מפני התקפות שליחה מחדש

כדי למנוע ממשתמשים זדוניים לעשות שימוש חוזר בתשובות קודמות מ-Play Integrity API, אפשר להשתמש בשדה nonce כדי לזהות באופן ייחודי כל הודעה.

כשמבקשים קביעת תקינות:

  1. צריך להשיג ערך ייחודי גלובלי באופן שלא מאפשר למשתמשים זדוניים לנחש אותו. לדוגמה, ערך כזה יכול להיות מספר אקראי מאובטח מבחינה קריפטוגרפית שנוצר בצד השרת, או מזהה קיים מראש, כמו מזהה סשן או מזהה עסקה. גרסה פשוטה יותר ופחות מאובטחת היא יצירת מספר אקראי במכשיר. מומלץ ליצור ערכים של 128 ביט ומעלה.
  2. קוראים לפונקציה setNonce() כדי להגדיר את השדה nonce לערך הייחודי משלב 1.

כשמקבלים קביעת תקינות:

  1. מפענחים את אסימון היושרה ומאמתים אותו, ומקבלים את הערך הייחודי מהשדה nonce.
  2. אם הערך משלב 1 נוצר בשרת, צריך לוודא שהערך הייחודי שהתקבל הוא אחד מהערכים שנוצרו, ושהוא נמצא בשימוש בפעם הראשונה (השרת צריך לשמור תיעוד של הערכים שנוצרו למשך זמן מתאים). אם הערך הייחודי שהתקבל כבר היה בשימוש או לא מופיע ברשומה, צריך לדחות את הבקשה
  3. אחרת, אם הערך הייחודי נוצר במכשיר, צריך לוודא שהערך שהתקבל נמצא בשימוש בפעם הראשונה (השרת צריך לשמור רשומה של ערכים שכבר נראו למשך זמן מתאים). אם הערך הייחודי שהתקבל כבר נמצא בשימוש, צריך לדחות את הבקשה.

שילוב של שתי ההגנות מפני פגיעה והתקפות שידור חוזר (מומלץ)

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

כשמבקשים קביעת תקינות:

  1. המשתמש יוזם את הפעולה בעלת הערך הגבוה.
  2. מקבלים ערך ייחודי לפעולה הזו כמו שמתואר בקטע הכללת ערכים ייחודיים כדי להגן מפני התקפות שליחה מחדש.
  3. כותבים את ההודעה שרוצים להגן עליה. כוללים בהודעה את הערך הייחודי משלב 2.
  4. האפליקציה מחשבת תקציר של ההודעה שהיא רוצה להגן עליה, כמו שמתואר בקטע הוספת גיבוב (hash) של בקשה כדי להגן מפני שינוי לא מורשה. מכיוון שההודעה מכילה את הערך הייחודי, הערך הייחודי הוא חלק מהגיבוב.
  5. משתמשים ב-setNonce() כדי להגדיר את השדה nonce לערך הגיבוב המחושב מהשלב הקודם.

כשמקבלים קביעת תקינות:

  1. קבלת הערך הייחודי מהבקשה
  2. מפענחים ומאמתים את טוקן השלמות, ומקבלים את הגיבוב מהשדה nonce.
  3. כמו שמתואר בקטע הוספת גיבוב של הבקשה כדי להגן מפני שינויים לא מורשים, מחשבים מחדש את הגיבוב בצד השרת ומוודאים שהוא תואם לגיבוב שהתקבל מאסימון השלמות.
  4. כמו שמתואר בקטע הכללת ערכים ייחודיים כדי להגן מפני מתקפות שידור חוזר, צריך לבדוק את התוקף של הערך הייחודי.

בתרשים הרצף הבא מוצגים השלבים האלה עם nonce בצד השרת:

איור 2. דיאגרמת רצף שמראה איך להגן מפני שיבוש ומתקפות חוזרות.

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

אחרי שיוצרים nonce, אפשר לבקש קביעת תקינות מ-Google Play. כדי לעשות זאת, פועלים לפי השלבים הבאים:

  1. יוצרים IntegrityManager, כמו בדוגמאות הבאות.
  2. יוצרים IntegrityTokenRequest ומספקים את nonce באמצעות השיטה setNonce() בכלי הבנייה המשויך. אפליקציות שמופצות באופן בלעדי מחוץ ל-Google Play וערכות SDK צריכות גם לציין את מספר הפרויקט שלהן ב-Google Cloud באמצעות השיטה setCloudProjectNumber(). אפליקציות ב-Google Play מקושרות לפרויקט Cloud ב-Play Console, ולא צריך להגדיר את מספר פרויקט Cloud בבקשה.
  3. משתמשים בחשבון הניהול כדי להתקשר אל requestIntegrityToken(), ומספקים את IntegrityTokenRequest.

Kotlin

// Receive the nonce from the secure server.
val nonce: String = ...

// Create an instance of a manager.
val integrityManager =
    IntegrityManagerFactory.create(applicationContext)

// Request the integrity token by providing a nonce.
val integrityTokenResponse: Task<IntegrityTokenResponse> =
    integrityManager.requestIntegrityToken(
        IntegrityTokenRequest.builder()
             .setNonce(nonce)
             .build())

Java

import com.google.android.gms.tasks.Task; ...

// Receive the nonce from the secure server.
String nonce = ...

// Create an instance of a manager.
IntegrityManager integrityManager =
    IntegrityManagerFactory.create(getApplicationContext());

// Request the integrity token by providing a nonce.
Task<IntegrityTokenResponse> integrityTokenResponse =
    integrityManager
        .requestIntegrityToken(
            IntegrityTokenRequest.builder().setNonce(nonce).build());

Unity

IEnumerator RequestIntegrityTokenCoroutine() {
    // Receive the nonce from the secure server.
    var nonce = ...

    // Create an instance of a manager.
    var integrityManager = new IntegrityManager();

    // Request the integrity token by providing a nonce.
    var tokenRequest = new IntegrityTokenRequest(nonce);
    var requestIntegrityTokenOperation =
        integrityManager.RequestIntegrityToken(tokenRequest);

    // Wait for PlayAsyncOperation to complete.
    yield return requestIntegrityTokenOperation;

    // Check the resulting error code.
    if (requestIntegrityTokenOperation.Error != IntegrityErrorCode.NoError)
    {
        AppendStatusLog("IntegrityAsyncOperation failed with error: " +
                requestIntegrityTokenOperation.Error);
        yield break;
    }

    // Get the response.
    var tokenResponse = requestIntegrityTokenOperation.GetResult();
}

Unreal Engine

// .h
void MyClass::OnRequestIntegrityTokenCompleted(
  EIntegrityErrorCode ErrorCode,
  UIntegrityTokenResponse* Response)
{
  // Check the resulting error code.
  if (ErrorCode == EIntegrityErrorCode::Integrity_NO_ERROR)
  {
    // Get the token.
    FString Token = Response->Token;
  }
}

// .cpp
void MyClass::RequestIntegrityToken()
{
  // Receive the nonce from the secure server.
  FString Nonce = ...

  // Create the Integrity Token Request.
  FIntegrityTokenRequest Request = { Nonce };

  // Create a delegate to bind the callback function.
  FIntegrityOperationCompletedDelegate Delegate;

  // Bind the completion handler (OnRequestIntegrityTokenCompleted) to the delegate.
  Delegate.BindDynamic(this, &MyClass::OnRequestIntegrityTokenCompleted);

  // Initiate the integrity token request, passing the delegate to handle the result.
  GetGameInstance()
    ->GetSubsystem<UIntegrityManager>()
    ->RequestIntegrityToken(Request, Delegate);
}

מותאמת

/// Create an IntegrityTokenRequest opaque object.
const char* nonce = RequestNonceFromServer();
IntegrityTokenRequest* request;
IntegrityTokenRequest_create(&request);
IntegrityTokenRequest_setNonce(request, nonce);

/// Prepare an IntegrityTokenResponse opaque type pointer and call
/// IntegerityManager_requestIntegrityToken().
IntegrityTokenResponse* response;
IntegrityErrorCode error_code =
        IntegrityManager_requestIntegrityToken(request, &response);

/// ...
/// Proceed to polling iff error_code == INTEGRITY_NO_ERROR
if (error_code != INTEGRITY_NO_ERROR)
{
    /// Remember to call the *_destroy() functions.
    return;
}
/// ...
/// Use polling to wait for the async operation to complete.
/// Note, the polling shouldn't block the thread where the IntegrityManager
/// is running.

IntegrityResponseStatus response_status;

/// Check for error codes.
IntegrityErrorCode error_code =
        IntegrityTokenResponse_getStatus(response, &response_status);
if (error_code == INTEGRITY_NO_ERROR
    && response_status == INTEGRITY_RESPONSE_COMPLETED)
{
    const char* integrity_token = IntegrityTokenResponse_getToken(response);
    SendTokenToServer(integrity_token);
}
/// ...
/// Remember to free up resources.
IntegrityTokenRequest_destroy(request);
IntegrityTokenResponse_destroy(response);
IntegrityManager_destroy();

פענוח ואימות של קביעת התקינות

כשמבקשים קביעת תקינות, Play Integrity API מספק טוקן תגובה חתום. ה-nonce שאתם כוללים בבקשה הופך לחלק מטוקן התגובה.

פורמט הטוקן

האסימון הוא JSON Web Token‏ (JWT) מוטמע, שהוא JSON Web Encryption‏ (JWE) של JSON Web Signature‏ (JWS). הרכיבים JWE ו-JWS מיוצגים באמצעות סריאליזציה קומפקטית .

אלגוריתמי ההצפנה והחתימה נתמכים היטב במגוון הטמעות של JWT:

  • ב-JWE נעשה שימוש ב-A256KW בשביל alg וב-A256GCM בשביל enc

  • ב-JWS נעשה שימוש ב-ES256.

פענוח ואימות בשרתים של Google (מומלץ)

‫Play Integrity API מאפשר לפענח ולאמת את קביעת התקינות בשרתים של Google, וכך לשפר את האבטחה של האפליקציה. כדי לעשות זאת, צריך לבצע את השלבים הבאים:

  1. יוצרים חשבון שירות בפרויקט Google Cloud שמקושר לאפליקציה.
  2. בשרת של האפליקציה, מאחזרים את אסימון הגישה מפרטי הכניסה של חשבון השירות באמצעות היקף ההרשאות playintegrity, ושולחים את הבקשה הבאה:

    playintegrity.googleapis.com/v1/PACKAGE_NAME:decodeIntegrityToken -d \
    '{ "integrity_token": "INTEGRITY_TOKEN" }'
  3. קוראים את תגובת ה-JSON.

פענוח ואימות מקומיים

אם תבחרו לנהל ולהוריד את המפתחות להצפנת תשובות, תוכלו לפענח ולאמת את האסימון שהוחזר בסביבת השרת המאובטחת שלכם. אפשר לקבל את הטוקן שהוחזר באמצעות השיטה IntegrityTokenResponse#token().

בדוגמה הבאה מוצג איך לפענח את מפתח ה-AES ואת מפתח ה-EC הציבורי בקידוד DER לאימות חתימה מ-Play Console למפתחות ספציפיים לשפה (במקרה הזה, שפת התכנות Java) בקצה העורפי של האפליקציה. הערה: המפתחות מקודדים ב-Base64 באמצעות דגלים שמוגדרים כברירת מחדל.

Kotlin

// base64OfEncodedDecryptionKey is provided through Play Console.
var decryptionKeyBytes: ByteArray =
    Base64.decode(base64OfEncodedDecryptionKey, Base64.DEFAULT)

// Deserialized encryption (symmetric) key.
var decryptionKey: SecretKey = SecretKeySpec(
    decryptionKeyBytes,
    /* offset= */ 0,
    AES_KEY_SIZE_BYTES,
    AES_KEY_TYPE
)

// base64OfEncodedVerificationKey is provided through Play Console.
var encodedVerificationKey: ByteArray =
    Base64.decode(base64OfEncodedVerificationKey, Base64.DEFAULT)

// Deserialized verification (public) key.
var verificationKey: PublicKey = KeyFactory.getInstance(EC_KEY_TYPE)
    .generatePublic(X509EncodedKeySpec(encodedVerificationKey))

Java

// base64OfEncodedDecryptionKey is provided through Play Console.
byte[] decryptionKeyBytes =
    Base64.decode(base64OfEncodedDecryptionKey, Base64.DEFAULT);

// Deserialized encryption (symmetric) key.
SecretKey decryptionKey =
    new SecretKeySpec(
        decryptionKeyBytes,
        /* offset= */ 0,
        AES_KEY_SIZE_BYTES,
        AES_KEY_TYPE);

// base64OfEncodedVerificationKey is provided through Play Console.
byte[] encodedVerificationKey =
    Base64.decode(base64OfEncodedVerificationKey, Base64.DEFAULT);
// Deserialized verification (public) key.
PublicKey verificationKey =
    KeyFactory.getInstance(EC_KEY_TYPE)
        .generatePublic(new X509EncodedKeySpec(encodedVerificationKey));

לאחר מכן, משתמשים במפתחות האלה כדי לפענח קודם את אסימון השלמות (חלק ה-JWE) ואז מאמתים ומחלצים את חלק ה-JWS המקונן.

Kotlin

val jwe: JsonWebEncryption =
    JsonWebStructure.fromCompactSerialization(integrityToken) as JsonWebEncryption
jwe.setKey(decryptionKey)

// This also decrypts the JWE token.
val compactJws: String = jwe.getPayload()

val jws: JsonWebSignature =
    JsonWebStructure.fromCompactSerialization(compactJws) as JsonWebSignature
jws.setKey(verificationKey)

// This also verifies the signature.
val payload: String = jws.getPayload()

Java

JsonWebEncryption jwe =
    (JsonWebEncryption)JsonWebStructure
        .fromCompactSerialization(integrityToken);
jwe.setKey(decryptionKey);

// This also decrypts the JWE token.
String compactJws = jwe.getPayload();

JsonWebSignature jws =
    (JsonWebSignature) JsonWebStructure.fromCompactSerialization(compactJws);
jws.setKey(verificationKey);

// This also verifies the signature.
String payload = jws.getPayload();

המטען הייעודי (payload) שמתקבל הוא טוקן של טקסט פשוט שמכיל פסקי דין שלמות.

תיקון בעיות שקשורות לתוצאות הבדיקה באמצעות הנחיה ב-Google Play (אופציונלי)

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

‫Play Integrity API מספק אפשרות להציג תיבת דו-שיח של Google Play שמבקשת מהמשתמש לבצע פעולה, למשל להוריד את הגרסה הרשמית של האפליקציה מ-Google Play.

במאמר תיבות דו-שיח לתיקון בעיות מוסבר איך להפעיל את תיבות הדו-שיח האלה מהאפליקציה על סמך התגובה של השרת.