หมวดหมู่ OWASP: MASVS-PLATFORM: การโต้ตอบกับแพลตฟอร์ม
ภาพรวม
การเปลี่ยนเส้นทาง Intent เกิดขึ้นเมื่อผู้โจมตีสามารถควบคุมเนื้อหาของ Intent ที่ใช้เปิดใช้งานคอมโพเนนต์ใหม่ในบริบทของแอปที่มีช่องโหว่ได้บางส่วนหรือทั้งหมด
คุณสามารถระบุ Intent ที่ใช้เปิดใช้งานคอมโพเนนต์ใหม่ได้หลายวิธี โดยวิธีที่พบบ่อยที่สุดคือเป็น Intent ที่แปลงเป็นอนุกรมในช่อง extras
หรือเป็นสตริงที่มาร์แชลแล้วและแยกวิเคราะห์ การควบคุมพารามิเตอร์บางส่วนอาจทําให้เกิดผลลัพธ์เดียวกันได้เช่นกัน
ผลกระทบ
ผลลัพธ์ที่ได้อาจแตกต่างกันไป ผู้โจมตีอาจเรียกใช้ฟีเจอร์ภายในในแอปที่มีช่องโหว่ หรืออาจเข้าถึงคอมโพเนนต์ส่วนตัว เช่น ออบเจ็กต์ ContentProvider ที่ไม่ได้ส่งออก
การลดปัญหา
โดยทั่วไปแล้ว อย่าแสดงฟีเจอร์ที่เกี่ยวข้องกับการเปลี่ยนเส้นทาง Intent ที่ฝังอยู่ ในกรณีที่หลีกเลี่ยงไม่ได้ ให้ใช้วิธีการบรรเทาผลกระทบต่อไปนี้
- กรองข้อมูลแบบรวมอย่างเหมาะสม โปรดอย่าลืมตรวจสอบหรือล้างการแจ้งว่าไม่เหมาะสม (
FLAG_GRANT_READ_URI_PERMISSION, FLAG_GRANT_WRITE_URI_PERMISSION, FLAG_GRANT_PERSISTABLE_URI_PERMISSION, and FLAG_GRANT_PREFIX_URI_PERMISSION
) และตรวจสอบว่าระบบเปลี่ยนเส้นทาง Intent ไปยังที่ใดIntentSanitizer
ช่วยคุณได้ในขั้นตอนนี้ - ใช้ออบเจ็กต์
PendingIntent
ซึ่งจะป้องกันไม่ให้มีการส่งออกคอมโพเนนต์และทำให้ Intent การดําเนินการเป้าหมายไม่เปลี่ยนแปลง
แอปจะตรวจสอบได้ว่ามีการเปลี่ยนเส้นทาง Intent ไปยังที่ใดโดยใช้เมธอดต่างๆ เช่น
ResolveActivity
Kotlin
val intent = getIntent()
// Get the component name of the nested intent.
val forward = intent.getParcelableExtra<Parcelable>("key") as Intent
val name: ComponentName = forward.resolveActivity(packageManager)
// Check that the package name and class name contain the expected values.
if (name.packagename == "safe_package" && name.className == "safe_class") {
// Redirect the nested intent.
startActivity(forward)
}
Java
Intent intent = getIntent()
// Get the component name of the nested intent.
Intent forward = (Intent) intent.getParcelableExtra("key");
ComponentName name = forward.resolveActivity(getPackageManager());
// Check that the package name and class name contain the expected values.
if (name.getPackageName().equals("safe_package") &&
name.getClassName().equals("safe_class")) {
// Redirect the nested intent.
startActivity(forward);
}
แอปสามารถใช้ IntentSanitizer
โดยใช้ตรรกะคล้ายกับตัวอย่างต่อไปนี้
Kotlin
val intent = IntentSanitizer.Builder()
.allowComponent("com.example.ActivityA")
.allowData("com.example")
.allowType("text/plain")
.build()
.sanitizeByThrowing(intent)
Java
Intent intent = new IntentSanitizer.Builder()
.allowComponent("com.example.ActivityA")
.allowData("com.example")
.allowType("text/plain")
.build()
.sanitizeByThrowing(intent);
การปกป้องเริ่มต้น
- Android 16 เปิดตัวโซลูชันการรักษาความปลอดภัยที่เข้มงวดโดยค่าเริ่มต้นเพื่อรับมือกับการโจมตีด้วยการเปลี่ยนเส้นทาง Intent
ความผิดพลาดที่พบบ่อย
- การตรวจสอบว่า
getCallingActivity()
แสดงผลค่าที่ไม่ใช่ค่า Null หรือไม่ แอปที่เป็นอันตรายอาจให้ค่า Null สำหรับฟังก์ชันนี้ - สมมติว่า
checkCallingPermission()
ทํางานในทุกบริบท หรือเมธอดจะโยนข้อยกเว้นเมื่อแสดงผลจํานวนเต็ม
ฟีเจอร์การแก้ไขข้อบกพร่อง
สําหรับแอปที่กำหนดเป้าหมายเป็น Android 12 (API ระดับ 31) ขึ้นไป คุณสามารถเปิดใช้ฟีเจอร์การแก้ไขข้อบกพร่อง ซึ่งในบางกรณีจะช่วยคุณตรวจจับได้ว่าแอปกำลังเปิดใช้งาน Intent ที่ไม่ปลอดภัยหรือไม่
หากแอปดำเนินการทั้ง 2 อย่างต่อไปนี้ ระบบจะตรวจพบการเริ่ม Intent ที่ไม่เป็นอันตราย และเกิดการละเมิด StrictMode
- แอปของคุณแยกแพ็กเกจ Intent ที่ฝังอยู่ออกจากส่วนเพิ่มเติมของ Intent ที่ส่ง
- แอปของคุณจะเริ่มคอมโพเนนต์แอปโดยใช้ Intent ที่ฝังไว้ทันที เช่น ส่ง Intent ไปยัง
startActivity()
,startService()
หรือbindService()