หน้านี้อธิบายวิธีตีความและใช้งานผลการตัดสินด้านความสมบูรณ์ที่ส่งคืน ไม่ว่าคุณจะส่งคำขอ API แบบมาตรฐานหรือแบบคลาสสิก ระบบจะแสดงผลการตัดสินความสมบูรณ์ ในรูปแบบเดียวกันที่มีเนื้อหาคล้ายกัน ผลการตัดสินด้านความสมบูรณ์จะสื่อสารข้อมูลเกี่ยวกับความถูกต้องของอุปกรณ์ แอป และบัญชี เซิร์ฟเวอร์ของแอปสามารถใช้เพย์โหลดที่ได้ในคำตัดสินที่ถอดรหัสแล้วและยืนยันแล้วเพื่อพิจารณาแนวทางที่ดีที่สุดในการดำเนินการหรือคำขอที่เฉพาะเจาะจงในแอป
รูปแบบผลการตัดสินความสมบูรณ์ที่แสดง
เพย์โหลดเป็น JSON ข้อความธรรมดาและมีสัญญาณความสมบูรณ์พร้อมกับ ข้อมูลที่นักพัฒนาแอปให้ไว้
โครงสร้างเพย์โหลดทั่วไปมีดังนี้
{ "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
ของเพย์โหลด 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
ของเพย์โหลด 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
ซึ่งมีป้ายกำกับอย่างน้อย 1 รายการที่แสดงถึงความสามารถของอุปกรณ์ในการบังคับใช้ความสมบูรณ์ของแอป
หากอุปกรณ์ไม่เป็นไปตามเกณฑ์ของป้ายกำกับใดๆ ฟิลด์ deviceIntegrity
จะไม่แสดง deviceRecognitionVerdict
"deviceIntegrity": { // "MEETS_DEVICE_INTEGRITY" is one of several possible values. "deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"] }
โดยค่าเริ่มต้น deviceRecognitionVerdict
อาจมีสิ่งต่อไปนี้
MEETS_DEVICE_INTEGRITY
- แอปกำลังทำงานบนอุปกรณ์ Android ของแท้ที่ได้รับการรับรอง ใน Android 13 ขึ้นไป จะมีหลักฐานที่ได้รับการสนับสนุนจากฮาร์ดแวร์ว่า Bootloader ของอุปกรณ์ล็อกอยู่และระบบปฏิบัติการ Android ที่โหลดเป็นอิมเมจของผู้ผลิตอุปกรณ์ที่ได้รับการรับรอง
- ว่าง (ค่าว่าง)
- แอปกําลังทํางานในอุปกรณ์ที่มีสัญญาณการโจมตี (เช่น การฮุก API) หรือการบุกรุกระบบ (เช่น การรูท) หรือแอปไม่ทํางานในอุปกรณ์จริง (เช่น โปรแกรมจําลองที่ไม่ผ่านการตรวจสอบความน่าเชื่อถือของ 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 จากโรงงานแล้ว (เช่น โดยการรีเซ็ตอุปกรณ์) และล็อก Bootloader แล้ว นอกจากนี้ คุณยังสร้างการทดสอบ Play Integrity API ใน Play Console ได้ด้วย
ป้ายกำกับอุปกรณ์แบบมีเงื่อนไข
หากแอปของคุณเผยแพร่ไปยัง Google Play Games สำหรับ PC deviceRecognitionVerdict
อาจมีป้ายกำกับต่อไปนี้ด้วย
MEETS_VIRTUAL_INTEGRITY
- แอปกำลังทำงานบนโปรแกรมจำลองที่ขับเคลื่อนโดย Android พร้อม บริการ Google Play โปรแกรมจำลองผ่านการตรวจสอบความสมบูรณ์ของระบบและเป็นไปตาม ข้อกำหนดหลักด้านความเข้ากันได้ของ Android
ข้อมูลอุปกรณ์และการเรียกคืนอุปกรณ์ (ไม่บังคับ)
หากเลือกรับป้ายกำกับเพิ่มเติมในการตัดสินความสมบูรณ์
deviceRecognitionVerdict
อาจมีป้ายกำกับเพิ่มเติมต่อไปนี้
MEETS_BASIC_INTEGRITY
- แอปกำลังทำงานบนอุปกรณ์ที่ผ่านการตรวจสอบความสมบูรณ์ของระบบพื้นฐาน
Bootloader ของอุปกรณ์อาจล็อกหรือปลดล็อกได้ และสถานะการเปิดเครื่องอาจ
ได้รับการยืนยันหรือไม่ก็ได้ อุปกรณ์อาจไม่ได้รับการรับรอง ในกรณีนี้ 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
version หากไม่เป็นไปตามข้อกําหนดที่จําเป็น ในกรณีนี้ ระบบจะไม่ตั้งค่าฟิลด์ 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
จะมีค่า 2 ค่าดังนี้
"deviceIntegrity": { "deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"], "recentDeviceActivity": { // "LEVEL_2" is one of several possible values. "deviceActivityLevel": "LEVEL_2" } }
คำจำกัดความของ deviceActivityLevel
จะแตกต่างกันไปในแต่ละโหมดและอาจมีค่าใดค่าหนึ่งต่อไปนี้
ระดับกิจกรรมล่าสุดในอุปกรณ์ | คำขอโทเค็นความสมบูรณ์ของ API มาตรฐานในอุปกรณ์นี้ ในชั่วโมงที่ผ่านมาต่อแอป | คำขอโทเค็นความสมบูรณ์ของ 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
จะแบ่งออกเป็น 2 ช่อง ดังนี้
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
มีค่าได้ 2 ค่า ได้แก่ 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
ที่มีการตอบกลับอย่างน้อย 1 รายการ การตอบกลับเหล่านี้จะอยู่ในกลุ่มใดกลุ่มหนึ่งต่อไปนี้
โดยขึ้นอยู่กับแหล่งที่มาของการติดตั้งแอปที่ตรวจพบ
แอป 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 Store ในอุปกรณ์ไม่ใช่เวอร์ชันล่าสุด
- บัญชีผู้ใช้ไม่มีใบอนุญาต Play
- ใช้คำขอมาตรฐานกับพารามิเตอร์
verdictOptOut
- มีการใช้คำขอมาตรฐานกับไลบรารี Play Integrity API เวอร์ชัน ที่ยังไม่รองรับความเสี่ยงในการเข้าถึงแอปสำหรับคำขอมาตรฐาน
ความเสี่ยงในการเข้าถึงแอปจะยกเว้นบริการช่วยเหลือที่ได้รับการยืนยันโดยอัตโนมัติ ซึ่งผ่านการตรวจสอบการช่วยเหลือของ Google Play ที่ได้รับการปรับปรุงแล้ว (ติดตั้งโดย App Store ใดก็ได้ในอุปกรณ์) "ยกเว้น" หมายความว่าบริการช่วยเหลือพิเศษที่ยืนยันแล้ว
ซึ่งทำงานในอุปกรณ์จะไม่แสดงการตอบกลับเกี่ยวกับการจับภาพ การควบคุม หรือ
การซ้อนทับในผลการตัดสินความเสี่ยงในการเข้าถึงแอป หากต้องการขอรับการตรวจสอบการช่วยเหลือพิเศษของ Google
Play ที่เพิ่มประสิทธิภาพสำหรับแอปการช่วยเหลือพิเศษ ให้เผยแพร่แอปใน Google
Play โดยตรวจสอบว่าแอปมีisAccessibilityTool
ตั้งค่าเป็น "จริง" ใน
ไฟล์ Manifest ของแอป หรือขอรับการตรวจสอบ
ตัวอย่างคำตัดสินความเสี่ยงในการเข้าถึงแอป
ตารางต่อไปนี้แสดงตัวอย่างผลการตัดสินความเสี่ยงในการเข้าถึงแอปและความหมายของผลการตัดสิน (ตารางนี้ไม่ได้แสดงผลลัพธ์ที่เป็นไปได้ทั้งหมด)
ตัวอย่างการตอบกลับคำตัดสินความเสี่ยงในการเข้าถึงแอป | การตีความ |
---|---|
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 จะมีการตัดสินของ Play Protect ดังนี้
"environmentDetails": {
"playProtectVerdict": "NO_ISSUES"
}
playProtectVerdict
อาจมีค่าใดค่าหนึ่งต่อไปนี้
NO_ISSUES
- Play Protect เปิดอยู่และไม่พบปัญหาเกี่ยวกับแอปในอุปกรณ์
NO_DATA
- Play Protect เปิดอยู่ แต่ยังไม่มีการสแกน อุปกรณ์หรือ แอป Play Store อาจเพิ่งได้รับการรีเซ็ต
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 ได้ ทั้งนี้ขึ้นอยู่กับความเสี่ยงที่คุณยอมรับได้ หากผู้ใช้ไม่สามารถปฏิบัติตามข้อกำหนดเหล่านี้ คุณสามารถบล็อกไม่ให้ผู้ใช้ดำเนินการในเซิร์ฟเวอร์ได้