หมวดหมู่ OWASP: MASVS-CODE: คุณภาพโค้ด
ภาพรวม
ความเสี่ยงที่เกี่ยวข้องกับสิทธิ์ที่กำหนดเองจะเกิดขึ้นเมื่อไม่มีคำจำกัดความของสิทธิ์ที่กำหนดเองหรือสะกดผิด หรือเมื่อมีการใช้แอตทริบิวต์ android:protectionLevel ที่เกี่ยวข้องในไฟล์ Manifest อย่างไม่ถูกต้อง
ตัวอย่างเช่น ความเสี่ยงเหล่านี้อาจถูกใช้ประโยชน์โดยการสร้างสิทธิ์ที่กำหนดเองที่มีชื่อเดียวกัน แต่กำหนดโดยแอปที่เป็นอันตรายและใช้ระดับการปกป้องที่แตกต่างกัน
สิทธิ์ที่กำหนดเองได้รับการออกแบบมาเพื่อให้แชร์ทรัพยากรและความสามารถกับแอปอื่นๆ ได้ ตัวอย่างการใช้สิทธิ์ที่กำหนดเองอย่างถูกต้องตามกฎหมายมีดังนี้
- ควบคุมการสื่อสารระหว่างกระบวนการ (IPC) ระหว่างแอป 2 แอปขึ้นไป
- เข้าถึงบริการของบุคคลที่สาม
- จำกัดการเข้าถึงข้อมูลที่แชร์ของแอป
ผลกระทบ
ผลกระทบจากการใช้ประโยชน์จากช่องโหว่นี้คือแอปที่เป็นอันตรายอาจได้รับสิทธิ์เข้าถึงทรัพยากรที่เดิมตั้งใจไว้ว่าจะได้รับการปกป้อง ผลกระทบของช่องโหว่ขึ้นอยู่กับทรัพยากรที่ได้รับการปกป้องและสิทธิ์ที่เชื่อมโยงของบริการแอปพลิเคชันเดิม
ความเสี่ยง: การสะกดผิดของสิทธิ์ที่กำหนดเอง
อาจมีการประกาศสิทธิ์ที่กำหนดเองในไฟล์ Manifest แต่มีการใช้สิทธิ์ที่กำหนดเองอื่นเพื่อปกป้องคอมโพเนนต์ Android ที่ส่งออกเนื่องจากการสะกดผิด แอปพลิเคชันที่เป็นอันตรายสามารถใช้ประโยชน์จากแอปพลิเคชันที่สะกดสิทธิ์ผิดได้โดยการดำเนินการอย่างใดอย่างหนึ่งต่อไปนี้
- ลงทะเบียนสิทธิ์นั้นก่อน
- คาดการณ์การสะกดคำในแอปพลิเคชันที่ตามมา
ซึ่งอาจทำให้แอปพลิเคชันเข้าถึงทรัพยากรโดยไม่ได้รับอนุญาตหรือควบคุมแอปพลิเคชันที่เป็นเหยื่อได้
ตัวอย่างเช่น แอปที่มีช่องโหว่ต้องการปกป้องคอมโพเนนต์โดยใช้สิทธิ์ READ_CONTACTS แต่สะกดสิทธิ์ผิดเป็น READ_CONACTS โดยไม่ตั้งใจ แอปที่เป็นอันตรายสามารถอ้างสิทธิ์ READ_CONACTS ได้เนื่องจากไม่มีแอปพลิเคชัน (หรือระบบ) ใดเป็นเจ้าของ และได้รับสิทธิ์เข้าถึงคอมโพเนนต์ที่ได้รับการปกป้อง อีกรูปแบบหนึ่งที่พบได้บ่อยของช่องโหว่นี้คือ android:permission=True ค่าต่างๆ เช่น true และ false ไม่ว่าจะเป็นตัวพิมพ์ใหญ่หรือตัวพิมพ์เล็ก ถือเป็นอินพุตที่ไม่ถูกต้องสำหรับการประกาศสิทธิ์และได้รับการปฏิบัติในลักษณะเดียวกับการสะกดผิดอื่นๆ ในการประกาศสิทธิ์ที่กำหนดเอง หากต้องการแก้ไขปัญหานี้ ให้เปลี่ยนค่าของแอตทริบิวต์ android:permission เป็นสตริงสิทธิ์ที่ถูกต้อง ตัวอย่างเช่น หากแอปต้องเข้าถึงรายชื่อติดต่อของผู้ใช้ ค่าของแอตทริบิวต์ android:permission ควรเป็น android.permission.READ_CONTACTS
การบรรเทา
การตรวจสอบ Lint ของ Android
เมื่อประกาศสิทธิ์ที่กำหนดเอง ให้ใช้การตรวจสอบ Lint ของ Android เพื่อช่วยคุณค้นหาการสะกดผิดและข้อผิดพลาดอื่นๆ ที่อาจเกิดขึ้นในโค้ด
แบบแผนการตั้งชื่อ
ใช้แบบแผนการตั้งชื่อที่สอดคล้องกันเพื่อให้การสะกดผิดสังเกตเห็นได้ง่ายขึ้น ตรวจสอบการประกาศสิทธิ์ที่กำหนดเองในไฟล์ Manifest ของแอปอย่างละเอียดว่ามีการสะกดผิดหรือไม่
ความเสี่ยง: สิทธิ์ที่ไม่มีแอปที่กำหนด
มีการใช้สิทธิ์เพื่อปกป้องทรัพยากรของแอป แอปสามารถประกาศสิทธิ์ที่จำเป็นสำหรับการเข้าถึงทรัพยากรได้ 2 ตำแหน่งที่แตกต่างกัน ดังนี้
- AndroidManifest.xml: กำหนดไว้ล่วงหน้าในไฟล์ AndroidManifest.xml (หากไม่ได้
ระบุไว้ ระบบจะใช้สิทธิ์
<application>) เช่น สิทธิ์ของผู้ให้บริการprovider permission สิทธิ์ของผู้รับreceiver permission สิทธิ์ของกิจกรรมactivity permission สิทธิ์ของบริการservice permission - โค้ด: ลงทะเบียนในโค้ดรันไทม์ เช่น
registerReceiver().
อย่างไรก็ตาม บางครั้งสิทธิ์เหล่านี้ไม่ได้กำหนดโดยแท็กที่เกี่ยวข้องในไฟล์ Manifest ของ APK ในอุปกรณ์
<permission> ในกรณีนี้ เราจะเรียกสิทธิ์เหล่านี้ว่าสิทธิ์ที่ไม่มีแอปที่กำหนด สถานการณ์นี้อาจเกิดขึ้นได้จากหลายสาเหตุ เช่น
- การอัปเดตในไฟล์ Manifest และโค้ดที่มีการตรวจสอบสิทธิ์อาจไม่ซิงค์กัน
- ระบบอาจไม่รวม APK ที่มีสิทธิ์ไว้ในการสร้าง หรืออาจรวมเวอร์ชันที่ไม่ถูกต้อง
- ชื่อสิทธิ์ในการตรวจสอบหรือในไฟล์ Manifest อาจสะกดผิด
แอปที่เป็นอันตรายอาจกำหนดสิทธิ์ที่ไม่มีแอปที่กำหนดและได้รับสิทธิ์นั้น หากเกิดกรณีนี้ แอปพลิเคชันที่มีสิทธิ์ซึ่งเชื่อถือสิทธิ์ที่ไม่มีแอปที่กำหนดเพื่อปกป้องคอมโพเนนต์อาจถูกบุกรุก
ในกรณีที่แอปที่มีสิทธิ์ใช้สิทธิ์เพื่อปกป้องหรือจำกัดคอมโพเนนต์ใดๆ การดำเนินการนี้อาจทำให้แอปที่เป็นอันตรายได้รับสิทธิ์เข้าถึงคอมโพเนนต์นั้น ตัวอย่างเช่น การเปิดใช้กิจกรรมที่ได้รับการปกป้องด้วยสิทธิ์ การเข้าถึงผู้ให้บริการเนื้อหา หรือการออกอากาศไปยัง Broadcast Receiver ที่ได้รับการปกป้องด้วยสิทธิ์ที่ไม่มีแอปที่กำหนด
นอกจากนี้ยังอาจทำให้แอปพลิเคชันที่มีสิทธิ์ถูกหลอกให้เชื่อว่าแอปที่เป็นอันตรายเป็นแอปที่ถูกต้องตามกฎหมายและโหลดไฟล์หรือเนื้อหา
การบรรเทา
ตรวจสอบว่าสิทธิ์ที่กำหนดเองทั้งหมดที่แอปใช้เพื่อปกป้องคอมโพเนนต์ได้รับการกำหนดไว้ในไฟล์ Manifest ด้วย
แอปใช้สิทธิ์ที่กำหนดเอง my.app.provider.READ และ my.app.provider.WRITE เพื่อปกป้องการเข้าถึงผู้ให้บริการเนื้อหา ดังนี้
Xml
<provider android:name="my.app.database.CommonContentProvider" android:readPermission="my.app.provider.READ" android:writePermission="my.app.provider.WRITE" android:exported="true" android:process=":myappservice" android:authorities="my.app.database.contentprovider"/>
แอปยังกำหนดและใช้สิทธิ์ที่กำหนดเองเหล่านี้ด้วย ซึ่งจะป้องกันไม่ให้แอปที่เป็นอันตรายอื่นๆ ทำเช่นนั้น
Xml
<permission android:name="my.app.provider.READ"/>
<permission android:name="my.app.provider.WRITE"/>
<uses-permission android:name="my.app.provider.READ" />
<uses-permission android:name="my.app.provider.WRITE" />
ความเสี่ยง: การใช้ android:protectionLevel อย่างไม่ถูกต้อง
แอตทริบิวต์นี้อธิบายระดับความเสี่ยงที่อาจเกิดขึ้นในสิทธิ์และระบุขั้นตอนที่ระบบควรปฏิบัติตามเมื่อตัดสินใจว่าจะให้สิทธิ์หรือไม่
การบรรเทา
หลีกเลี่ยงระดับการปกป้องปกติหรืออันตราย
การใช้ protectionLevel ปกติ หรืออันตราย กับสิทธิ์หมายความว่าแอปส่วนใหญ่สามารถขอและได้รับสิทธิ์
- "ปกติ" กำหนดให้ประกาศเท่านั้น
- "อันตราย" ผู้ใช้จำนวนมากจะอนุมัติ
ดังนั้น protectionLevels เหล่านี้จึงให้การรักษาความปลอดภัยเพียงเล็กน้อย
ใช้สิทธิ์ลายเซ็น (Android >= 10)
ใช้ระดับการปกป้องลายเซ็นทุกครั้งที่ทำได้ การใช้ความสามารถนี้จะช่วยให้มั่นใจได้ว่ามีเพียงแอปอื่นๆ ที่ลงชื่อด้วยใบรับรองเดียวกันกับแอปที่สร้างสิทธิ์เท่านั้นที่จะเข้าถึงฟีเจอร์ที่ได้รับการปกป้องเหล่านั้นได้ ตรวจสอบว่าคุณใช้ใบรับรองการลงชื่อเฉพาะ (ไม่ได้นำกลับมาใช้ซ้ำ) และจัดเก็บใบรับรองอย่างปลอดภัยใน Keystore
กำหนดสิทธิ์ที่กำหนดเองดังนี้ในไฟล์ Manifest
Xml
<permission
android:name="my.custom.permission.MY_PERMISSION"
android:protectionLevel="signature"/>
จำกัดการเข้าถึง เช่น กิจกรรม ให้เฉพาะแอปที่ได้รับสิทธิ์ที่กำหนดเองนี้ ดังนี้
Xml
<activity android:name=".MyActivity" android:permission="my.custom.permission.MY_PERMISSION"/>
แอปอื่นๆ ที่ลงชื่อด้วยใบรับรองเดียวกันกับแอปที่ประกาศสิทธิ์ที่กำหนดเองนี้จะได้รับสิทธิ์เข้าถึงกิจกรรม .MyActivity และต้องประกาศสิทธิ์ดังกล่าวในไฟล์ Manifest ดังนี้
Xml
<uses-permission android:name="my.custom.permission.MY_PERMISSION" />
ระวังสิทธิ์ที่กำหนดเองของลายเซ็น (Android < 10)
หากแอปกำหนดเป้าหมายเป็น Android < 10 เมื่อใดก็ตามที่ระบบนำสิทธิ์ที่กำหนดเองของแอปออกเนื่องจากการถอนการติดตั้งหรือการอัปเดต อาจมีแอปที่เป็นอันตรายที่ยังคงใช้สิทธิ์ที่กำหนดเองเหล่านั้นได้และข้ามการตรวจสอบ ซึ่งเป็นผลมาจากช่องโหว่การยกระดับสิทธิ์ (CVE-2019-2200) ที่ได้รับการ
แก้ไขใน Android 10
นี่เป็นเหตุผลหนึ่ง (นอกเหนือจากความเสี่ยงของภาวะแข่งขัน) ที่เราแนะนำให้ใช้การตรวจสอบลายเซ็นแทนสิทธิ์ที่กำหนดเอง
ความเสี่ยง: ภาวะแข่งขัน
หากแอปที่ถูกต้องตามกฎหมาย A กำหนดสิทธิ์ที่กำหนดเองของลายเซ็นที่แอป X อื่นๆ ใช้ แต่ต่อมามีการถอนการติดตั้งแอป A แอปที่เป็นอันตราย B สามารถกำหนดสิทธิ์ที่กำหนดเองเดียวกันนั้นด้วย protectionLevel ที่แตกต่างกัน เช่น ปกติ ด้วยวิธีนี้ B จะได้รับสิทธิ์เข้าถึงคอมโพเนนต์ทั้งหมดที่ได้รับการปกป้องด้วยสิทธิ์ที่กำหนดเองนั้นในแอป X โดยไม่จำเป็นต้องลงชื่อด้วยใบรับรองเดียวกันกับแอป A
กรณีเดียวกันนี้จะเกิดขึ้นหากมีการติดตั้ง B ก่อน A
การบรรเทา
หากต้องการให้คอมโพเนนต์พร้อมใช้งานเฉพาะแอปที่ลงชื่อด้วยลายเซ็นเดียวกันกับแอปที่ให้บริการ คุณอาจหลีกเลี่ยงการกำหนดสิทธิ์ที่กำหนดเองเพื่อจำกัดการเข้าถึงคอมโพเนนต์นั้นได้ ในสถานการณ์นี้ คุณสามารถใช้การตรวจสอบลายเซ็นได้ เมื่อแอปแอปหนึ่งของคุณส่งคำขอไปยังแอปอีกแอปหนึ่ง แอปที่ 2 จะตรวจสอบได้ว่าทั้ง 2 แอปลงชื่อด้วยใบรับรองเดียวกันก่อนที่จะปฏิบัติตามคำขอ
แหล่งข้อมูล
- ลดคำขอสิทธิ์
- ภาพรวมสิทธิ์
- คำอธิบายระดับการปกป้อง
- CustomPermissionTypo Android Lint
- วิธีใช้ Android Lint
- บทความงานวิจัยพร้อมคำอธิบายเชิงลึกเกี่ยวกับสิทธิ์ของ Android และผลการทดสอบ Fuzz ที่น่าสนใจ