การเปลี่ยนเส้นทาง Intent

หมวดหมู่ 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);

ความผิดพลาดที่พบบ่อย

  • การตรวจสอบว่า getCallingActivity() แสดงผลค่าที่ไม่ใช่ค่า Null หรือไม่ แอปที่เป็นอันตรายอาจให้ค่า Null สำหรับฟังก์ชันนี้
  • สมมติว่า checkCallingPermission() ใช้งานได้ในทุกบริบท หรือเมธอดส่งข้อยกเว้นเมื่อแสดงผลจำนวนเต็มจริงๆ

ฟีเจอร์การแก้ไขข้อบกพร่อง

สําหรับแอปที่กำหนดเป้าหมายเป็น Android 12 (API ระดับ 31) ขึ้นไป คุณสามารถเปิดใช้ฟีเจอร์การแก้ไขข้อบกพร่อง ซึ่งในบางกรณีจะช่วยคุณตรวจจับได้ว่าแอปกำลังเปิดใช้งาน Intent ที่ไม่ปลอดภัยหรือไม่

หากแอปดำเนินการทั้ง 2 อย่างต่อไปนี้ ระบบจะตรวจพบการเริ่ม Intent ที่ไม่เป็นอันตราย และเกิดการละเมิด StrictMode

  • แอปของคุณแยกแพ็กเกจ Intent ที่ฝังอยู่ออกจากส่วนเพิ่มเติมของ Intent ที่ส่ง
  • แอปของคุณจะเริ่มคอมโพเนนต์แอปโดยใช้ Intent ที่ฝังอยู่นั้นทันที เช่น ส่ง Intent ไปยัง startActivity(), startService() หรือ bindService()

แหล่งข้อมูล