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