หมวดหมู่ 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>
) เช่น สิทธิ์ของผู้ให้บริการ สิทธิ์ของผู้รับ สิทธิ์ของกิจกรรม สิทธิ์ของบริการ - โค้ด: ลงทะเบียนในโค้ดรันไทม์ เช่น
registerReceiver()
อย่างไรก็ตาม บางครั้งสิทธิ์เหล่านี้ไม่ได้กำหนดโดยแท็ก <permission>
ที่เกี่ยวข้องในไฟล์ Manifest ของ APK ในอุปกรณ์ ในกรณีนี้ สิทธิ์ดังกล่าวจะเรียกว่าสิทธิ์ที่ไม่มีเจ้าของ ปัญหานี้อาจเกิดขึ้นได้จากหลายสาเหตุ เช่น
- การอัปเดตในไฟล์ Manifest กับโค้ดที่มีการตรวจสอบสิทธิ์อาจไม่ได้ซิงค์กัน
- APK ที่มีสิทธิ์อาจไม่รวมอยู่ในบิลด์ หรืออาจรวมเวอร์ชันที่ไม่ถูกต้อง
- ชื่อสิทธิ์ในการตรวจสอบหรือไฟล์ Manifest อาจสะกดไม่ถูกต้อง
แอปที่เป็นอันตรายอาจกำหนดสิทธิ์ที่ไม่มีเจ้าของและรับสิทธิ์ดังกล่าว หากเกิดกรณีเช่นนี้ แอปพลิเคชันที่มีสิทธิ์ซึ่งเชื่อถือสิทธิ์ที่ไม่มีเจ้าของเพื่อปกป้องคอมโพเนนต์อาจถูกบุกรุก
ในกรณีที่แอปที่มีสิทธิ์ใช้สิทธิ์เพื่อปกป้องหรือจํากัดคอมโพเนนต์ใดก็ตาม การดำเนินการนี้อาจให้สิทธิ์แอปที่เป็นอันตรายเข้าถึงคอมโพเนนต์นั้น ตัวอย่างเช่น การเริ่มกิจกรรมที่ได้รับการคุ้มครองโดยสิทธิ์ การเข้าถึงผู้ให้บริการเนื้อหา หรือการออกอากาศไปยังตัวรับสัญญาณออกอากาศที่ได้รับการคุ้มครองโดยสิทธิ์ที่ไม่มีเจ้าของ
นอกจากนี้ยังอาจสร้างสถานการณ์ที่แอปพลิเคชันที่มีสิทธิ์ถูกหลอกให้เชื่อว่าแอปที่เป็นอันตรายเป็นแอปที่ถูกต้องตามกฎหมาย จึงโหลดไฟล์หรือเนื้อหา
การลดปัญหา
ตรวจสอบว่าสิทธิ์ที่กำหนดเองทั้งหมดที่แอปใช้เพื่อปกป้องคอมโพเนนต์ได้รับการกำหนดไว้ในไฟล์ 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
ปกติหรืออันตรายในสิทธิ์หมายความว่าแอปส่วนใหญ่จะขอและรับสิทธิ์ได้ ดังนี้
- "normal" กำหนดให้ประกาศเท่านั้น
- "อันตราย" จะได้รับอนุมัติจากผู้ใช้จำนวนมาก
ดังนั้น protectionLevels
เหล่านี้จึงมีความปลอดภัยน้อย
ใช้สิทธิ์ลายเซ็น (Android เวอร์ชันตั้งแต่ 10 ขึ้นไป)
ใช้ระดับการปกป้องลายเซ็นเมื่อเป็นไปได้ การใช้ความสามารถนี้จะช่วยให้มั่นใจได้ว่ามีเพียงแอปอื่นๆ ที่ลงนามด้วยใบรับรองเดียวกับแอปที่สร้างสิทธิ์เท่านั้นที่จะเข้าถึงฟีเจอร์ที่ได้รับการปกป้องเหล่านั้นได้ ตรวจสอบว่าคุณใช้ใบรับรองการรับรองเฉพาะ (ไม่ได้ใช้ซ้ำ) และจัดเก็บไว้ในคีย์สโตร์อย่างปลอดภัย
กำหนดสิทธิ์ที่กำหนดเองในไฟล์ 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
อื่นๆ แต่มีการถอนการติดตั้งแอปดังกล่าวในภายหลัง แอปที่เป็นอันตราย B
จะกำหนดสิทธิ์ที่กำหนดเองเดียวกันนั้นด้วย protectionLevel
อื่นได้ เช่น normal วิธีนี้จะช่วยให้ B
ได้รับสิทธิ์เข้าถึงคอมโพเนนต์ทั้งหมดที่ได้รับการปกป้องโดยสิทธิ์ที่กำหนดเองในแอป X
โดยไม่ต้องลงนามด้วยใบรับรองเดียวกับแอป A
การดำเนินการนี้จะเหมือนกันหากติดตั้ง B
ก่อน A
การลดปัญหา
หากต้องการทำให้คอมโพเนนต์พร้อมใช้งานสำหรับแอปที่ลงนามด้วยลายเซ็นเดียวกับแอปที่ให้บริการเท่านั้น คุณอาจหลีกเลี่ยงการกำหนดสิทธิ์ที่กำหนดเองเพื่อจำกัดการเข้าถึงคอมโพเนนต์นั้นได้ ในกรณีนี้ คุณสามารถใช้การตรวจสอบลายเซ็นได้ เมื่อแอปหนึ่งส่งคำขอไปยังแอปอื่น แอปที่ 2 จะยืนยันได้ว่าทั้ง 2 แอปได้รับการรับรองด้วยใบรับรองเดียวกันก่อนที่จะปฏิบัติตามคำขอ
แหล่งข้อมูล
- ลดคำขอสิทธิ์
- ภาพรวมสิทธิ์
- คำอธิบายระดับการป้องกัน
- CustomPermissionTypo Android Lint
- วิธีใช้ Android Lint
- บทความวิจัยที่มีคำอธิบายโดยละเอียดเกี่ยวกับสิทธิ์ของ Android และผลการทดสอบ Fuzz ที่น่าสนใจ