หมวดหมู่ OWASP: MASVS-CODE: คุณภาพโค้ด
ภาพรวม
เมื่อจัดเก็บหรือโอนข้อมูลออบเจ็กต์ Java จำนวนมาก การจัดรูปแบบข้อมูลให้เป็นอนุกรมก่อนมักจะมีประสิทธิภาพมากกว่า จากนั้นข้อมูลจะเข้าสู่กระบวนการดีซีเรียลไลซ์โดยแอปพลิเคชัน กิจกรรม หรือผู้ให้บริการที่ได้รับซึ่งจะจัดการข้อมูลนั้น ภายใต้สถานการณ์ปกติ ระบบจะจัดรูปแบบข้อมูลและจัดรูปแบบข้อมูลอีกครั้งโดยที่ผู้ใช้ไม่ต้องดำเนินการใดๆ อย่างไรก็ตาม ผู้ไม่ประสงค์ดีอาจละเมิดความสัมพันธ์ของความไว้วางใจระหว่างกระบวนการแปลงค่ากลับเป็นรูปแบบเดิมกับออบเจ็กต์ที่ต้องการได้ เช่น ขัดขวางและแก้ไขออบเจ็กต์ที่แปลงค่าเป็นรูปแบบเดิม ซึ่งจะทำให้ผู้ไม่ประสงค์ดีสามารถทำการโจมตีได้ เช่น การปฏิเสธการให้บริการ (DoS) การเพิ่มสิทธิ์ และการเรียกใช้โค้ดจากระยะไกล (RCE)
แม้ว่าคลาส Serializable
จะเป็นเมธอดทั่วไปในการจัดการการแปลงเป็นอนุกรม แต่ Android ก็มีคลาสของตัวเองสำหรับจัดการการแปลงเป็นอนุกรมที่เรียกว่า Parcel
เมื่อใช้คลาส Parcel
คุณสามารถจัดรูปแบบข้อมูลออบเจ็กต์เป็นข้อมูลสตรีมไบต์และแพ็กลงใน Parcel
โดยใช้อินเทอร์เฟซ Parcelable
วิธีนี้จะช่วยให้ขนส่งหรือจัดเก็บ Parcel
ได้อย่างมีประสิทธิภาพมากขึ้น
อย่างไรก็ตาม คุณควรพิจารณาอย่างรอบคอบเมื่อใช้คลาส Parcel
เนื่องจากมีไว้เพื่อเป็นกลไกการขนส่ง IPC ที่มีประสิทธิภาพสูง แต่ไม่ควรใช้เพื่อจัดเก็บออบเจ็กต์ที่แปลงเป็นอนุกรมภายในพื้นที่เก็บข้อมูลถาวรในเครื่อง เนื่องจากอาจทำให้เกิดปัญหาความเข้ากันได้ของข้อมูลหรือการสูญเสียข้อมูล เมื่อต้องอ่านข้อมูล คุณสามารถใช้อินเทอร์เฟซ Parcelable
เพื่อแปลงค่า Parcel
ให้เป็นรูปแบบเดิมและเปลี่ยนกลับเป็นข้อมูลออบเจ็กต์ได้
เวกเตอร์หลัก 3 รายการสำหรับการใช้ประโยชน์จากการจัดรูปแบบข้อมูลอีกครั้งใน Android มีดังนี้
- ใช้ประโยชน์จากการคาดเดาที่ไม่ถูกต้องของนักพัฒนาแอปว่าการแยกวิเคราะห์ออบเจ็กต์ที่มาจากคลาสประเภทที่กำหนดเองนั้นปลอดภัย ในทางปฏิบัติ ออบเจ็กต์ที่มาจากคลาสใดก็ตามอาจถูกแทนที่ด้วยเนื้อหาที่เป็นอันตราย ซึ่งในกรณีที่เลวร้ายที่สุดอาจรบกวนโปรแกรมโหลดคลาสของแอปพลิเคชันเดียวกันหรือแอปพลิเคชันอื่นๆ การแทรกแซงนี้อยู่ในรูปแบบของการแทรกค่าที่เป็นอันตราย ซึ่งอาจนำไปสู่การลักลอบนำข้อมูลออกหรือการควบคุมบัญชีโดยขึ้นอยู่กับวัตถุประสงค์ของคลาส
- การใช้ประโยชน์จากวิธีการดีซีเรียลไลซ์ที่การออกแบบถือว่าไม่ปลอดภัย (ตัวอย่างเช่น CVE-2023-35669 ซึ่งเป็นข้อบกพร่องในการโจมตีเพื่อยกระดับสิทธิ์ในเครื่องที่อนุญาตการแทรกโค้ด JavaScript ที่กำหนดเองผ่านเวกเตอร์ดีซีเรียลไลซ์ของ Deep Link)
- การใช้ประโยชน์จากข้อบกพร่องในตรรกะแอปพลิเคชัน (เช่น CVE-2023-20963 ซึ่งเป็นข้อบกพร่องของการโจมตีเพื่อยกระดับสิทธิ์ภายในที่อนุญาตให้แอปดาวน์โหลดและเรียกใช้โค้ดภายในสภาพแวดล้อมที่ได้รับสิทธิ์ผ่านข้อบกพร่องในตรรกะพัสดุของ WorkSource ของ Android)
ผลกระทบ
แอปพลิเคชันใดก็ตามที่แปลงข้อมูลอนุกรมที่ไม่น่าเชื่อถือหรือเป็นอันตรายอาจเสี่ยงต่อการดําเนินการโค้ดจากระยะไกลหรือการโจมตีด้วยการปฏิเสธการให้บริการ
ความเสี่ยง: การดีอนุกรมของอินพุตที่ไม่น่าเชื่อถือ
ผู้โจมตีอาจใช้ประโยชน์จากการไม่ยืนยันพัสดุภายในตรรกะของแอปพลิเคชันเพื่อแทรกออบเจ็กต์ที่กำหนดเอง ซึ่งเมื่อแปลงค่ากลับแล้วอาจบังคับให้แอปพลิเคชันเรียกใช้โค้ดที่เป็นอันตรายซึ่งอาจส่งผลให้เกิดการปฏิเสธการให้บริการ (DoS) การยกระดับสิทธิ์ และการดำเนินการโค้ดจากระยะไกล (RCE)
การโจมตีประเภทนี้อาจสังเกตได้ยาก ตัวอย่างเช่น แอปพลิเคชันอาจมี Intent ที่คาดหวังพารามิเตอร์เพียงรายการเดียว ซึ่งหลังจากตรวจสอบแล้ว ระบบจะแปลงข้อมูลอีกครั้ง หากผู้โจมตีส่งพารามิเตอร์พิเศษที่เป็นอันตรายที่ไม่คาดคิดรายการที่ 2 พร้อมกับพารามิเตอร์ที่คาดไว้ จะทำให้ออบเจ็กต์ข้อมูลทั้งหมดที่แทรกถูกดีซีเรียลไลซ์เนื่องจาก Intent จะถือว่าโค้ดเสริมเป็น Bundle
ผู้ใช้ที่เป็นอันตรายอาจใช้ลักษณะการทำงานนี้เพื่อแทรกข้อมูลออบเจ็กต์ที่เมื่อดีซีเรียลไลซ์แล้วอาจทำให้เกิด RCE, ข้อมูลถูกบุกรุก หรือสูญหาย
การลดปัญหา
แนวทางปฏิบัติแนะนำคือให้ถือว่าข้อมูลซีเรียลทั้งหมดไม่น่าเชื่อถือและอาจเป็นอันตราย ตรวจสอบความสมบูรณ์ของข้อมูลที่แปลงเป็นอนุกรม โดยตรวจสอบว่าข้อมูลเป็นคลาสและรูปแบบที่ถูกต้องตามที่แอปพลิเคชันคาดไว้
โซลูชันที่เป็นไปได้อาจเป็นการใช้รูปแบบมองล่วงหน้าสำหรับไลบรารี java.io.ObjectInputStream
การแก้ไขโค้ดที่รับผิดชอบในการแปลงข้อมูลย้อนกลับช่วยให้มั่นใจได้ว่าจะมีการแปลงข้อมูลย้อนกลับเฉพาะชุดคลาสที่ระบุไว้อย่างชัดเจนภายใน Intent
ตั้งแต่ Android 13 (API ระดับ 33) ได้มีการอัปเดตเมธอดหลายรายการภายในคลาส Intent
ซึ่งถือว่าเป็นทางเลือกที่ปลอดภัยกว่าเมธอดเก่าๆ ที่เลิกใช้งานแล้วสำหรับการจัดการพัสดุ เมธอดใหม่ที่ปลอดภัยกว่าประเภทเหล่านี้ เช่น getParcelableExtra(java.lang.String, java.lang.Class)
และ getParcelableArrayListExtra(java.lang.String, java.lang.Class)
จะดำเนินการตรวจสอบประเภทข้อมูลเพื่อจับจุดอ่อนที่ไม่ตรงกันซึ่งอาจทำให้แอปพลิเคชันขัดข้องและอาจถูกนำไปใช้โจมตีเพื่อยกระดับสิทธิ์ เช่น CVE-2021-0928
ตัวอย่างต่อไปนี้แสดงวิธีใช้งานคลาส Parcel
เวอร์ชันที่ปลอดภัย
สมมติว่าคลาส UserParcelable
ใช้ Parcelable
และสร้างอินสแตนซ์ของข้อมูลผู้ใช้ซึ่งจะเขียนลงใน Parcel
จากนั้น จะใช้วิธี readParcelable
ที่ปลอดภัยกว่าต่อไปนี้เพื่ออ่านพัสดุไปรษณีย์แบบเรียงอันดับได้
Kotlin
val parcel = Parcel.obtain()
val userParcelable = parcel.readParcelable(UserParcelable::class.java.classLoader)
Java
Parcel parcel = Parcel.obtain();
UserParcelable userParcelable = parcel.readParcelable(UserParcelable.class, UserParcelable.CREATOR);
สังเกตการใช้ UserParcelable.CREATOR
ในเมธอดของตัวอย่าง Java ด้านบน พารามิเตอร์ที่จำเป็นนี้จะบอกเมธอด readParcelable
ว่าจะพบในประเภทใดและมีประสิทธิภาพมากกว่าเมธอด readParcelable
เวอร์ชันที่เลิกใช้งานแล้ว
ความเสี่ยงที่เฉพาะเจาะจง
ส่วนนี้จะรวบรวมความเสี่ยงที่ต้องใช้กลยุทธ์การบรรเทาความเสี่ยงที่ไม่ใช่มาตรฐานหรือได้รับการบรรเทาในระดับ SDK บางระดับ และอยู่ที่นี่เพื่อความสมบูรณ์
ความเสี่ยง: การจัดรูปแบบออบเจ็กต์ใหม่ที่ไม่พึงประสงค์
การติดตั้งใช้งานอินเทอร์เฟซ Serializable
ภายในคลาสจะทําให้คลาสย่อยทั้งหมดของคลาสนั้นติดตั้งใช้งานอินเทอร์เฟซโดยอัตโนมัติ ในสถานการณ์นี้ ออบเจ็กต์บางรายการอาจรับค่าอินเทอร์เฟซที่กล่าวถึงข้างต้น ซึ่งหมายความว่าระบบจะยังคงประมวลผลออบเจ็กต์ที่เฉพาะเจาะจงซึ่งไม่ได้มีไว้สำหรับการแปลงค่ากลับ
ซึ่งอาจเพิ่มพื้นที่การโจมตีโดยไม่ตั้งใจ
การลดปัญหา
หากคลาสรับค่าอินเทอร์เฟซ Serializable
ตามคำแนะนำของ OWASP คุณควรใช้เมธอด readObject
ดังนี้เพื่อหลีกเลี่ยงไม่ให้ชุดออบเจ็กต์ในคลาสได้รับการแปลงข้อมูลอีกครั้ง
Kotlin
@Throws(IOException::class)
private final fun readObject(in: ObjectInputStream) {
throw IOException("Cannot be deserialized")
}
Java
private final void readObject(ObjectInputStream in) throws java.io.IOException {
throw new java.io.IOException("Cannot be deserialized");
}
แหล่งข้อมูล
- พาร์เซล
- แปลงที่ดิน
- Serializable
- Intent
- ช่องโหว่การแปลงค่ากลับของ Android: ประวัติโดยย่อ
- Android Parcels: The Bad, the Good and the Better (วิดีโอ)
- Android Parcels: The Bad, the Good and the Better (presentation slides)
- CVE-2014-7911: การโจมตีเพื่อยกระดับสิทธิ์ใน Android <5.0 โดยใช้ ObjectInputStream
- CVE-CVE-2017-0412
- CVE-2021-0928: การแปลงอนุกรมที่ดิน/การแยกซีเรียลไลซ์ไม่ตรงกัน
- คำแนะนำของ OWASP