หากคุณวางแผนที่จะสร้าง API มาตรฐานเท่านั้น ของคำขอ ซึ่งเหมาะสำหรับผู้ใช้ส่วนใหญ่ นักพัฒนาซอฟต์แวร์คุณสามารถข้ามไปที่ความซื่อสัตย์ คำตัดสิน หน้านี้อธิบายการสร้างแบบคลาสสิก คําขอ API สําหรับการตัดสินความสมบูรณ์ ซึ่งรองรับใน Android 4.4 (API ระดับ 19) ขึ้นไป
ข้อควรพิจารณา
เปรียบเทียบคำขอมาตรฐานและคำขอแบบคลาสสิก
คุณสามารถสร้างคำขอมาตรฐาน คำขอแบบคลาสสิก หรือทั้ง 2 อย่างรวมกันก็ได้ ตามความต้องการด้านความปลอดภัยและการป้องกันการละเมิดของแอป คำขอมาตรฐานคือ เหมาะสำหรับแอปและเกมทั้งหมด และสามารถใช้เพื่อตรวจสอบว่า การเรียกใช้เซิร์ฟเวอร์เป็นความจริง ขณะมอบการป้องกันบางอย่างไม่ให้สามารถเล่นซ้ำได้ และการขโมยข้อมูลไปยัง Google Play คำขอแบบคลาสสิกมีราคาแพงกว่าและ คุณต้องรับผิดชอบการติดตั้งใช้งาน บรรทัดดังกล่าวอย่างถูกต้องเพื่อป้องกัน การขโมยข้อมูลและการโจมตีบางประเภท ควรส่งคำขอแบบคลาสสิกน้อยลง บ่อยกว่าคำขอมาตรฐาน เช่น เป็นแบบครั้งเดียวเพื่อตรวจสอบ การกระทำที่มีคุณค่าสูงหรือมีความละเอียดอ่อนเป็นการกระทำจริงหรือไม่
ตารางต่อไปนี้จะเน้นความแตกต่างที่สำคัญระหว่าง คำขอ:
คําขอ API มาตรฐาน | คําขอ API แบบคลาสสิก | |
---|---|---|
สิ่งที่ต้องมีก่อน | ||
ต้องมีเวอร์ชัน Android SDK ขั้นต่ำ | Android 5.0 (API ระดับ 21) ขึ้นไป | Android 4.4 (API ระดับ 19) ขึ้นไป |
ข้อกำหนดของ Google Play | Google Play Store และบริการ Google Play | Google Play Store และบริการ Google Play |
รายละเอียดการผสานรวม | ||
ต้องอุ่นเครื่อง API | ✔️ (ไม่กี่วินาที) | ❌ |
เวลาในการตอบสนองคำขอโดยทั่วไป | ไม่กี่ร้อยมิลลิวินาที | ไม่กี่วินาที |
ความถี่ของคำขอที่เป็นไปได้ | บ่อย (การตรวจสอบการดำเนินการหรือคำขอตามคำขอ) | ไม่บ่อย (การตรวจสอบแบบครั้งเดียวสำหรับการดำเนินการที่มีมูลค่าสูงสุดหรือคำขอที่มีความละเอียดอ่อนมากที่สุด) |
หมดเวลา | อุ่นเครื่องส่วนใหญ่จะสั้นกว่า 10 วินาที แต่เกี่ยวข้องกับการเรียกใช้เซิร์ฟเวอร์ เราจึงขอแนะนำให้ใช้ระยะหมดเวลาที่นาน (เช่น 1 นาที) คำขอคำตัดสินเกิดขึ้นจากฝั่งไคลเอ็นต์ | คำขอส่วนใหญ่ต่ำกว่า 10 วินาที แต่เกี่ยวข้องกับการเรียกใช้เซิร์ฟเวอร์ ดังนั้นขอแนะนำให้ตั้งระยะหมดเวลาที่นาน (เช่น 1 นาที) |
โทเค็นการตัดสินความสมบูรณ์ | ||
มีรายละเอียดอุปกรณ์ แอป และบัญชี | ✔️ | ✔️ |
การแคชโทเค็น | การแคชในอุปกรณ์ที่ได้รับการคุ้มครองโดย Google Play | ไม่แนะนำ |
ถอดรหัสและยืนยันโทเค็นผ่านเซิร์ฟเวอร์ Google Play | ✔️ | ✔️ |
เวลาในการตอบสนองของคำขอถอดรหัสแบบเซิร์ฟเวอร์ต่อเซิร์ฟเวอร์ตามปกติ | 10 วินาทีของมิลลิวินาทีที่มีความพร้อมใช้งาน 3-9 วินาที | 10 วินาทีของมิลลิวินาทีที่มีความพร้อมใช้งาน 3-9 วินาที |
ถอดรหัสและยืนยันโทเค็นในเครื่องในสภาพแวดล้อมเซิร์ฟเวอร์ที่ปลอดภัย | ❌ | ✔️ |
ถอดรหัสและยืนยันโทเค็นฝั่งไคลเอ็นต์ | ❌ | ❌ |
ความใหม่ของการตัดสินความสมบูรณ์ | Google Play จะแคชและรีเฟรชอัตโนมัติบางส่วน | คำตัดสินทั้งหมดที่คำนวณใหม่สำหรับคำขอแต่ละรายการ |
ข้อจำกัด | ||
คำขอต่อแอปต่อวัน | 10,000 รายการโดยค่าเริ่มต้น (ขอเพิ่มได้) | 10,000 รายการโดยค่าเริ่มต้น (ขอเพิ่มได้) |
คำขอต่ออินสแตนซ์แอปต่อนาที | อุ่นเครื่อง: 5 ครั้งต่อนาที โทเค็นความสมบูรณ์: ไม่มีขีดจำกัดสาธารณะ* |
โทเค็นความสมบูรณ์: 5 ต่อนาที |
การป้องกัน | ||
ป้องกันการปลอมแปลงและการโจมตีในลักษณะเดียวกัน | ใช้ช่อง requestHash |
ใช้ช่อง nonce กับการเชื่อมโยงเนื้อหาตามข้อมูลคำขอ |
ลดการต่อต้านการเล่นซ้ำและการโจมตีที่คล้ายกัน | การผ่อนปรนชั่วคราวโดย Google Play | ใช้ช่อง nonce กับตรรกะฝั่งเซิร์ฟเวอร์ |
* คำขอทั้งหมด รวมถึงคำขอที่ไม่จำกัดแบบสาธารณะ อยู่ภายใต้ขีดจำกัดการป้องกันที่ไม่เปิดเผยต่อสาธารณะ
สร้างคำขอแบบคลาสสิกไม่บ่อย
การสร้างโทเค็นความสมบูรณ์ต้องใช้เวลา ข้อมูล และแบตเตอรี่ และแต่ละแอปจะมี จำนวนคำขอแบบคลาสสิกสูงสุดที่สร้างได้ต่อวัน ดังนั้นคุณควร สร้างเฉพาะคำขอแบบคลาสสิกเพื่อตรวจสอบมูลค่าสูงสุดหรือการดำเนินการที่มีความละเอียดอ่อนที่สุด เป็นของแท้เมื่อคุณต้องการให้การรับประกันเพิ่มเติมสำหรับคำขอมาตรฐาน คุณ ไม่ควรส่งคำขอแบบเดิมสำหรับการดำเนินการที่ใช้ความถี่สูงหรือมูลค่าต่ำ สิ่งที่ไม่ควรทำ ส่งคำขอแบบคลาสสิกทุกครั้งที่แอปย้ายไปยังเบื้องหน้าหรือทุก 2-3 ใช้งานในเบื้องหลัง และหลีกเลี่ยงการโทรจากอุปกรณ์จำนวนมากใน ในเวลาเดียวกัน แอปที่ส่งคำขอแบบคลาสสิกมากเกินไปอาจถูกควบคุมให้ เพื่อปกป้องผู้ใช้จากการติดตั้งใช้งานที่ไม่ถูกต้อง
หลีกเลี่ยงการแคชคำตัดสิน
การแคชผลการตัดสินจะเพิ่มความเสี่ยงของการโจมตี เช่น การขโมยข้อมูล และการเล่นซ้ำ ที่จะนำคำตัดสินที่ดีมาใช้ซ้ำจากสภาพแวดล้อมที่ไม่น่าเชื่อถือ หากคุณ ให้พิจารณาส่งคำขอแบบคลาสสิก แล้วแคชไว้ใช้ในภายหลัง แนะนำให้ส่งคำขอมาตรฐานแบบออนดีมานด์แทน คำขอมาตรฐาน เกี่ยวข้องกับการแคชบางส่วนในอุปกรณ์ แต่ Google Play ใช้การปกป้องเพิ่มเติม เทคนิคที่ช่วยลดความเสี่ยงของการโจมตีซ้ำและการขโมยข้อมูล
ใช้ช่อง Nonce เพื่อปกป้องคำขอแบบคลาสสิก
Play Integrity API มีช่องชื่อ nonce
ซึ่งสามารถใช้เพื่อ
ปกป้องแอปของคุณจากการโจมตีบางอย่างเพิ่มเติม เช่น การเล่นซ้ำและการสร้างความเสียหาย
การโจมตี Play Integrity API จะแสดงค่าที่คุณตั้งค่าไว้ในช่องนี้ภายใน
การตอบกลับด้านความสมบูรณ์ที่ลงนามแล้ว ปฏิบัติตามคำแนะนำอย่างละเอียดเกี่ยวกับวิธีสร้าง
nonces สำหรับปกป้องแอปของคุณจากการโจมตี
ลองส่งคำขอแบบคลาสสิกอีกครั้งด้วย Exponential Backoff
สภาวะแวดล้อม เช่น การเชื่อมต่ออินเทอร์เน็ตที่ไม่เสถียรหรือ อุปกรณ์ทำงานหนักเกินไป อาจทำให้การตรวจสอบความสมบูรณ์ของอุปกรณ์ล้มเหลว ซึ่งอาจส่งผลถึง ไม่มีการสร้างป้ายกำกับสำหรับอุปกรณ์ที่เชื่อถือได้ ถึง คุณสามารถลดสถานการณ์เหล่านี้ได้ โดยให้รวมตัวเลือกการลองอีกครั้งที่มี Exponential Backoff
ภาพรวม
เมื่อผู้ใช้ดำเนินการที่มีมูลค่าสูงในแอปซึ่งคุณต้องการปกป้อง ด้วยการตรวจสอบความสมบูรณ์ ให้ทำตามขั้นตอนต่อไปนี้
- แบ็กเอนด์ฝั่งเซิร์ฟเวอร์ของแอปจะสร้างและส่งค่าที่ไม่ซ้ำกันไปยัง และฝั่งไคลเอ็นต์ ขั้นตอนที่เหลือจะอ้างอิงตรรกะนี้ว่า "แอป"
- แอปของคุณสร้าง
nonce
จากค่าที่ไม่ซ้ำกันและเนื้อหา การกระทำที่มีมูลค่าสูง จากนั้นจะเรียก Play Integrity API ซึ่งจะส่งในnonce
- แอปของคุณได้รับผลการตัดสินที่ลงนามและเข้ารหัสจาก Play Integrity API
- แอปของคุณส่งผลการตัดสินที่ลงนามและเข้ารหัสไปยังแบ็กเอนด์ของแอปแล้ว
- แบ็กเอนด์ของแอปจะส่งคำตัดสินไปยังเซิร์ฟเวอร์ Google Play ทั้งนี้ Google เซิร์ฟเวอร์ Play จะถอดรหัสและยืนยันผลการตัดสิน และส่งคืนผลลัพธ์ไปยัง ของแบ็กเอนด์ของแอป
- แบ็กเอนด์ของแอปจะช่วยกำหนดวิธีดำเนินการต่อโดยพิจารณาจากสัญญาณที่มีอยู่ใน เพย์โหลดโทเค็น
- แบ็กเอนด์ของแอปจะส่งผลการตัดสินใจไปยังแอป
สร้าง Nonce
เมื่อปกป้องการดำเนินการในแอปด้วย Play Integrity API คุณจะทำสิ่งต่อไปนี้ได้
ใช้ประโยชน์จากฟิลด์ nonce
เพื่อลดการโจมตีบางประเภท เช่น
การโจมตีแบบ Person-in-the-middle (PITM) และการโจมตีแบบเล่นซ้ำ เดอะเพลย์
Integrity API จะแสดงค่าที่คุณกำหนดไว้ในช่องนี้ภายในฟิลด์ที่ลงนาม
การตอบกลับด้านความสมบูรณ์
ค่าที่ตั้งไว้ในช่อง nonce
ต้องมีรูปแบบที่ถูกต้อง:
String
- ปลอดภัยสำหรับ URL
- เข้ารหัสเป็น Base64 และไม่มีการรวม
- ต้องมีอักขระอย่างน้อย 16 ตัว
- มีอักขระได้สูงสุด 500 ตัว
ตัวอย่างวิธีทั่วไปในการใช้ช่อง nonce
ใน Play มีดังนี้
Integrity API หากต้องการการปกป้องที่รัดกุมที่สุดจาก nonce
คุณสามารถรวม
วิธีการด้านล่าง
ใส่แฮชคำขอเพื่อป้องกันการปลอมแปลง
คุณสามารถใช้พารามิเตอร์ nonce
ในคำขอ API แบบคลาสสิกได้ในลักษณะเดียวกับ
requestHash
ในคำขอ API มาตรฐานเพื่อปกป้องเนื้อหาของ
คำขอเกี่ยวกับการปลอมแปลง
เมื่อคุณขอการตัดสินความสมบูรณ์:
- คำนวณไดเจสต์ของพารามิเตอร์คำขอที่สำคัญทั้งหมด (เช่น SHA256 ของพารามิเตอร์ คำขอการทำให้เป็นอนุกรม) จากการดำเนินการของผู้ใช้หรือคำขอของเซิร์ฟเวอร์ที่ ยังเกิดขึ้นอยู่
- ใช้
setNonce
เพื่อตั้งค่าช่องnonce
เป็นค่าของไดเจสต์ที่คำนวณแล้ว
เมื่อคุณได้รับการตัดสินความสมบูรณ์:
- ถอดรหัสและตรวจสอบโทเค็นความสมบูรณ์ แล้วรับไดเจสต์จาก
nonce
- คำนวณสรุปของคำขอในลักษณะเดียวกับในแอป (เช่น SHA256 ของการเรียงลำดับคำขอแบบคงที่)
- เปรียบเทียบไดเจสต์ฝั่งเซิร์ฟเวอร์และฝั่งเซิร์ฟเวอร์ หากไม่ตรงกัน ระบบจะ คำขอไม่น่าเชื่อถือ
ใส่ค่าที่ไม่ซ้ำกันเพื่อป้องกันการโจมตีแบบเล่นซ้ำ
เพื่อป้องกันไม่ให้ผู้ใช้ที่มีเจตนาร้ายใช้คำตอบก่อนหน้านี้จาก
Play Integrity API คุณสามารถใช้ช่อง nonce
เพื่อระบุแต่ละรายการโดยไม่ซ้ำกันได้
เมื่อคุณขอการตัดสินความสมบูรณ์:
- ได้รับค่าที่ไม่ซ้ำกันทั่วโลกในแบบที่ผู้ใช้ที่เป็นอันตรายไม่อาจคาดเดาได้ ตัวอย่างเช่น หมายเลขสุ่มเพื่อความปลอดภัยแบบเข้ารหัสลับที่สร้างขึ้นใน ฝั่งเซิร์ฟเวอร์อาจเป็นค่า หรือรหัสที่มีอยู่แล้ว เช่น เซสชัน หรือ รหัสธุรกรรม ตัวแปรที่ง่ายขึ้นและปลอดภัยน้อยลงคือการสร้างแบบสุ่ม หมายเลขในอุปกรณ์ เราขอแนะนำให้สร้างค่าที่ไม่ต่ำกว่า 128 บิต
- เรียกใช้
setNonce()
เพื่อตั้งค่าช่องnonce
เป็นค่าที่ไม่ซ้ำจากขั้นตอนที่ 1
เมื่อคุณได้รับการตัดสินความสมบูรณ์:
- ถอดรหัสและยืนยันโทเค็นความสมบูรณ์ แล้วรับค่าที่ไม่ซ้ำกันจาก
nonce
- หากมีการสร้างค่าจากขั้นตอนที่ 1 บนเซิร์ฟเวอร์ ให้ตรวจสอบว่าค่า ได้รับค่าที่ไม่ซ้ำเป็นหนึ่งในค่าที่สร้างขึ้น ที่ใช้เป็นครั้งแรก (เซิร์ฟเวอร์ของคุณจะต้องเก็บบันทึกของ สำหรับระยะเวลาที่เหมาะสม) หากใช้ค่าที่ไม่ซ้ำกันที่ได้รับ อยู่แล้วหรือไม่ปรากฏในระเบียน ปฏิเสธคำขอ
- ไม่เช่นนั้น หากมีการสร้างค่าที่ไม่ซ้ำกันในอุปกรณ์ ให้ตรวจสอบว่าค่า จะมีการใช้ค่าที่ได้รับเป็นครั้งแรก (เซิร์ฟเวอร์ของคุณจะต้อง บันทึกค่าที่เห็นแล้วในระยะเวลาที่เหมาะสม) หากฟิลด์ได้รับ มีการใช้ค่าที่ไม่ซ้ำกันแล้ว โปรดปฏิเสธคำขอ
รวมการป้องกันการโจมตีแบบสอดแทรกและการโจมตีซ้ำเข้าด้วยกัน (แนะนำ)
คุณสามารถใช้ฟิลด์ nonce
เพื่อป้องกันทั้งการปลอมแปลงและ
การโจมตีซ้ำไปพร้อมกัน โดยสร้างค่าที่ไม่ซ้ำกันเป็น
ที่อธิบายไว้ข้างต้น และใส่ข้อมูลนี้เป็นส่วนหนึ่งของคำขอของคุณ จากนั้นคำนวณค่า
แฮชคำขอ อย่าลืมใส่ค่าที่ไม่ซ้ำกันเป็นส่วนหนึ่งของแฮช CANNOT TRANSLATE
ดังนี้
เมื่อคุณขอการตัดสินความสมบูรณ์:
- ผู้ใช้เป็นผู้เริ่มการดำเนินการที่มีมูลค่าสูง
- รับค่าที่ไม่ซ้ำกันสำหรับการกระทำนี้ตามที่อธิบายไว้ในคอลัมน์รวมที่ไม่ซ้ำ ค่าต่างๆ เพื่อป้องกันการโจมตีแบบเล่นซ้ำ
- เตรียมข้อความที่ต้องการปกป้อง ระบุค่าที่ไม่ซ้ำกันจากขั้นตอนที่ 2 ในข้อความ
- แอปของคุณจะคำนวณสรุปข้อความที่ต้องการปกป้อง เช่น ที่อธิบายไว้ในหัวข้อรวมแฮชคำขอเพื่อป้องกัน การงัดแงะ เนื่องจากข้อความจะมีแท็ก ค่าที่ไม่ซ้ำกันจะเป็นส่วนหนึ่งของแฮช
- ใช้
setNonce()
เพื่อตั้งค่าช่องnonce
เป็นไดเจสต์ที่คำนวณจาก ขั้นตอนก่อนหน้า
เมื่อคุณได้รับการตัดสินความสมบูรณ์:
- รับค่าที่ไม่ซ้ำจากคำขอ
- ถอดรหัสและตรวจสอบโทเค็นความสมบูรณ์ แล้วรับไดเจสต์จาก
nonce
- ตามที่อธิบายไว้ในส่วนรวมแฮชคำขอเพื่อป้องกันการปลอมแปลง ให้คำนวณไดเจสต์อีกครั้งทางฝั่งเซิร์ฟเวอร์ และตรวจสอบว่าตรงกับ ไดเจสต์ที่ได้จากโทเค็นความสมบูรณ์
- ตามที่อธิบายไว้ในส่วนรวมค่าที่ไม่ซ้ำกันเพื่อป้องกันไม่ให้มีการเล่นซ้ำ การโจมตี ให้ตรวจสอบความถูกต้องของค่าที่ไม่ซ้ำ
แผนภาพลำดับต่อไปนี้แสดงขั้นตอนเหล่านี้ในฝั่งเซิร์ฟเวอร์
nonce
:
ขอการตัดสินความสมบูรณ์
หลังจากสร้าง nonce
คุณจะขอการตัดสินความสมบูรณ์จาก Google ได้
เล่น โดยทำตามขั้นตอนต่อไปนี้
- สร้าง
IntegrityManager
ดังที่แสดงในตัวอย่างต่อไปนี้ - สร้าง
IntegrityTokenRequest
โดยระบุnonce
ผ่านทางsetNonce()
ในเครื่องมือสร้างที่เกี่ยวข้อง แอปที่เผยแพร่โดยเฉพาะ ภายนอก Google Play และ SDK ก็จะต้องระบุ หมายเลขโปรเจ็กต์ผ่านเมธอดsetCloudProjectNumber()
แอปใน Google Play จะลิงก์กับโปรเจ็กต์ที่อยู่ในระบบคลาวด์ใน Play Console และไม่จำเป็นต้อง กำหนดหมายเลขโปรเจ็กต์ที่อยู่ในระบบคลาวด์ในคำขอ ใช้ผู้จัดการเพื่อโทรหา
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());
เอกภาพ
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(); }
เนทีฟ
/// 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 จะแสดงโดยใช้คอมแพ็คท์ การเรียงอันดับ ที่ใช้เวลาเพียง 2 นาที
รองรับอัลกอริทึมการเข้ารหัส / การลงนามใน JWT ต่างๆ การนำไปใช้งาน:
ถอดรหัสและยืนยันบนเซิร์ฟเวอร์ของ Google (แนะนำ)
Play Integrity API ช่วยให้คุณสามารถถอดรหัสและยืนยันผลการตัดสินความสมบูรณ์ใน เซิร์ฟเวอร์ของ Google ซึ่งช่วยเพิ่มความปลอดภัยให้กับแอปของคุณ โดยทำตามขั้นตอนต่อไปนี้ ขั้นตอน:
- สร้างบัญชีบริการ ในโปรเจ็กต์ Google Cloud ที่ลิงก์กับแอปของคุณ
ในเซิร์ฟเวอร์ของแอป ให้ดึงข้อมูลโทเค็นเพื่อการเข้าถึงจากบัญชีบริการ ข้อมูลเข้าสู่ระบบโดยใช้ขอบเขต
playintegrity
และส่งคำขอต่อไปนี้playintegrity.googleapis.com/v1/PACKAGE_NAME:decodeIntegrityToken -d \ '{ "integrity_token": "INTEGRITY_TOKEN" }'
อ่านการตอบสนอง JSON
ถอดรหัสและยืนยันในเครื่อง
หากเลือกจัดการและดาวน์โหลดคีย์การเข้ารหัสการตอบกลับ คุณจะทำสิ่งต่อไปนี้ได้
ถอดรหัสและยืนยันโทเค็นที่แสดงผลภายในสภาพแวดล้อมเซิร์ฟเวอร์ที่ปลอดภัยของคุณเอง
คุณสามารถรับโทเค็นที่ส่งคืนได้โดยใช้ IntegrityTokenResponse#token()
ตัวอย่างต่อไปนี้แสดงวิธีถอดรหัสคีย์ AES และคีย์สาธารณะที่เข้ารหัส DER คีย์ EC สำหรับการยืนยันลายเซ็นจาก 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();
เพย์โหลดที่ได้คือโทเค็นข้อความธรรมดาที่มีความสมบูรณ์ คำตัดสิน