หมวดหมู่ OWASP: MASVS-CODE: คุณภาพของโค้ด
ภาพรวม
การโหลด URI ที่ไม่ปลอดภัยเกิดขึ้นเมื่อแอปพลิเคชัน Android ประเมินความถูกต้องของ URI ไม่ถูกต้องก่อนที่จะโหลดลงใน WebView
สาเหตุพื้นฐานที่อยู่เบื้องหลังช่องโหว่ประเภทนี้คือ URI ประกอบด้วยหลายส่วน ซึ่งอย่างน้อยที่สุดจะต้องมีการยืนยัน (เช่น การเพิ่มในรายการที่อนุญาต) รูปแบบและโฮสต์ (ของส่วนการให้สิทธิ์) ก่อนที่จะโหลด URI ไปยัง WebView หรือใช้ภายในแอปพลิเคชัน
ข้อผิดพลาดที่พบบ่อยที่สุดมีดังนี้
- ตรวจสอบโฮสต์แต่ไม่ตรวจสอบรูปแบบ ซึ่งจะทำให้ผู้โจมตีใช้รูปแบบต่างๆ เช่น
http://
,content://
หรือjavascript://
กับโฮสต์ที่ได้รับการตรวจสอบสิทธิ์ได้ - การแยกวิเคราะห์ URI ไม่ถูกต้อง โดยเฉพาะในกรณีที่ได้รับ URI เป็นสตริง
- ตรวจสอบรูปแบบ แต่ไม่ใช่โฮสต์ (การตรวจสอบโฮสต์ไม่เพียงพอ)
ในกรณีสุดท้ายนี้ มักเกิดขึ้นเมื่อแอปพลิเคชันต้องอนุญาตโดเมนย่อยที่กำหนดเองของโดเมนหลัก ดังนั้น แม้ว่าจะมีการดึงชื่อโฮสต์อย่างถูกต้อง แต่แอปจะใช้วิธีการต่างๆ เช่น startsWith
, endsWith,
หรือ contains
ของคลาส java.lang.String
เพื่อตรวจสอบว่ามีโดเมนหลักอยู่ในส่วนสตริงที่ดึงออกมาหรือไม่ หากใช้วิธีการเหล่านี้อย่างไม่ถูกต้อง อาจทำให้ได้ผลลัพธ์ที่ไม่ถูกต้องและบังคับให้แอปพลิเคชันเชื่อถือโฮสต์ที่อาจเป็นอันตรายอย่างไม่เหมาะสม
ผลกระทบ
ผลกระทบอาจแตกต่างกันไปตามบริบทที่ใช้โฮสต์ ในกรณีที่การโหลด URI ที่เป็นอันตราย (เช่น URI ที่หลีกเลี่ยงการกรอง/รายการที่อนุญาต) ใน WebView อาจทำให้เกิดการลักลอบใช้บัญชี (เช่น การใช้ฟิชชิง) การเรียกใช้โค้ด (เช่น การโหลด JavaScript ที่เป็นอันตราย) หรือการบุกรุกอุปกรณ์ (โค้ดที่ใช้ช่องโหว่ซึ่งส่งผ่านไฮเปอร์ลิงก์)
การลดปัญหา
เมื่อจัดการ URI สตริง สิ่งสำคัญคือต้องแยกวิเคราะห์สตริงเป็น URI และ ตรวจสอบทั้งรูปแบบและโฮสต์
Kotlin
fun isUriTrusted(incomingUri: String, trustedHostName: String): Boolean {
try {
val uri = Uri.parse(incomingUri)
return uri.scheme == "https" && uri.host == trustedHostName
} catch (e: NullPointerException) {
throw NullPointerException("incomingUri is null or not well-formed")
}
}
Java
public static boolean isUriTrusted(String incomingUri, String trustedHostName)
throws NullPointerException {
try {
Uri uri = Uri.parse(incomingUri);
return uri.getScheme().equals("https") &&
uri.getHost().equals(trustedHostName);
} catch (NullPointerException e) {
throw new NullPointerException(
"incomingUri is null or not well-formed");
}
}
สำหรับการตรวจสอบโฮสต์ หลังจากแยกส่วน URI ที่เกี่ยวข้องแล้ว คุณควร
ตรวจสอบทั้งส่วน (ไม่ใช่บางส่วน) เพื่อระบุได้อย่างถูกต้องว่า
โฮสต์เชื่อถือได้หรือไม่ เมื่อหลีกเลี่ยงการใช้วิธีการต่างๆ เช่น startsWith
หรือ endsWith
ไม่ได้
คุณควรใช้ไวยากรณ์ที่ถูกต้องและไม่มองข้ามอักขระหรือสัญลักษณ์ที่จำเป็น (เช่น endsWith
ต้องมีอักขระจุด ".
" ก่อนชื่อโดเมนเพื่อให้ตรงกันอย่างถูกต้อง) การละเลยอักขระเหล่านี้อาจทำให้การจับคู่ไม่ถูกต้องและกระทบต่อความปลอดภัย เนื่องจากโดเมนย่อยซ้อนกันได้ไม่จำกัด การจับคู่นิพจน์ทั่วไปจึงไม่ใช่กลยุทธ์ที่แนะนำสำหรับการตรวจสอบชื่อโฮสต์
ผู้ร่วมให้ข้อมูล: Dimitrios Valsamaras และ Michael Peck จาก Microsoft Threat Intelligence