อย่างที่นักพัฒนารู้กันดีว่านับตั้งแต่ Target API Level 31 (Android 12) เป็นต้นมา จะต้องกำหนด Flag ที่ชื่อว่า PendingIntent.FLAG_MUTABLE
หรือ PendingIntent.FLAG_IMMUTABLE
ให้กับ Pending Intent ด้วยเสมอ ไม่เช่นนั้นจะทำให้แอปพัง
ยกตัวอย่างเช่น เจ้าของบล็อกสร้าง Pending Intent สำหรับ Notification ขึ้นมาโดยไม่ได้กำหนด Flag ดังกล่าว เมื่อแอปทำงานบน Android 12 หรือสูงกว่าก็จะทำให้แอปพังและได้ IllegalArgumentException แทน
FATAL EXCEPTION: main
Process: com.akexorcist.sleepingforless, PID: 10890
java.lang.IllegalArgumentException: com.akexorcist.notification.pendingintentflag: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality depends on the PendingIntent being mutable, e.g. if it needs to be used with inline replies or bubbles.
และเจ้าของบล็อกก็ไม่รู้เหมือนกันว่าทำไมมันถึงพัง แต่ที่รู้คือต้องใส่ PendingIntent.FLAG_IMMUTABLE
หรือ PendingIntent.FLAG_MUTABLE
เพื่อให้แอปทำงานได้ปกติ
แล้วเราทำไปทำไมกันนะ 🤔?
สำหรับผู้ที่หลงเข้ามาอ่านคนใดอยากรู้จักกับ Pending Intent มากกว่านี้สามารถตามไปอ่านเพิ่มเติมได้จากบทความ Intent และ Pending Intent — ส่งใจ ไปหาเธอ
ช่องโหว่ด้านความปลอดภัยใน Pending Intent
Pending Intent เป็นหนึ่งในข้อมูลที่สามารถรับส่งระหว่าง App Component ได้ รวมไปถึงการส่งข้อมูลข้ามระหว่างแอปด้วยเช่นกัน แต่ที่นักพัฒนาน่าจะคุ้นเคยกันมากที่สุดก็คือการใช้งานร่วมกับ Notification เพื่อให้ผู้ใช้กด Notification แล้วเปิด Activity พร้อมแนบข้อมูลมาให้ด้วย
และเดิมทีนั้น Pending Intent เป็นแบบ Mutable มาตลอด ทำให้เพิ่มข้อมูล (Fill In) บางอย่างเข้าไปใน Pending Intent ได้ ทำให้มีโอกาสที่จะกลายเป็นช่องโหว่ในบางรูปแบบได้ เพราะอาจจะถูก App In The Middle ดักข้อมูลระหว่างทางหรือเพิ่มข้อมูลเพื่อหลอกให้ส่งข้อมูลกลับไปหาแอปเหล่านั้นได้
สามารถอ่านเพิ่มเติมได้ที่ "Having fun with secure messengers and Android Wear and Android Auto" by Artem Chaykin at CanSecWest2016 (หาวีดีโอย้อนหลังไม่เจอ)
Immutable Pending Intent ใน API Level 23 (Android 6.0 Marshmallow)
เนื่องจากมีแค่ Pending Intent ในบางกรณีเท่านั้นที่จำเป็นต้องเพิ่มข้อมูลเข้าไปทีหลัง จึงทำให้ทีมแอนดรอยด์เพิ่ม PendingIntent.FLAG_IMMUTABLE
เข้ามาใน API Level 23 (Android 6.0 Marshmallow) เพื่อไม่ให้เพิ่มข้อมูล (Fill In) เข้าไปใน Pending Intent ทีหลังได้
val pendingIntent = PendingIntent.getActivity(
context = context,
requestCode = 0,
intent = Intent(intentAction),
flags = PendingIntent.FLAG_IMMUTABLE,
)
หรือจะใช้ร่วมกับ Flag ตัวอื่นที่ไม่ใช่ FLAG_MUTABLE
ก็ได้เช่นกัน
val pendingIntent = PendingIntent.getActivity(
context = context,
requestCode = 0,
intent = Intent(intentAction),
flags = PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_ONE_SHOT,
)
โดยใน API Level 30 (Android 11) จะต้องกำหนด FLAG_MUTABLE
เพื่อทำให้ Pending Intent เป็น Mutable
และแอปที่กำหนด Target API Level 31 (Android 12) หรือสูงกว่าจะบังคับให้นักพัฒนากำหนด FLAG_MUTABLE
หรือ FLAG_IMMUTABLE
ให้กับ Pending Intent ด้วยเสมอ
และนั่นก็คือที่มาของบทความนี้นั่นเอง
Pending Intent แบบไหนควรกำหนดเป็น Mutable และแบบไหนเป็น Immutable
มี Pending Intent แค่บางรูปแบบเท่านั้นที่ต้องกำหนดเป็น Mutable โดยจะมีดังนี้
- Pending Intent ใน Notification ที่รองรับการตอบกลับผ่าน Notification Actions (Direct reply actions in notifications)
- Pending Intent ใน Notification ที่ทำงานร่วมกับ Android Auto ผ่านคลาส
CarAppExtender
- Pending Intent ใน Notification สำหรับบทสนทนา (Conversation) ที่รองรับ Bubble API
- การกำหนด Pending Intent เพื่อขอตำแหน่งปัจจุบันของอุปกรณ์ (Location Access) ในคำสั่ง
requestLocationUpdates
ของLocationManager
- การกำหนด Pending Intent ใน
AlarmManager
นอกเหนือจากนั้นให้กำหนดเป็น Immutable ทั้งหมด
สรุป
เนื่องจาก Pending Intent ถูกออกแบบให้เป็น Mutable มาตั้งแต่แรกและทำให้เกิดช่องโหว่ด้านความปลอดภัยสำหรับแอปที่มีการใช้งาน Pending Intent ในบางรูปแบบ จึงทำให้ระบบแอนดรอยด์รองรับ Immutable ใน Pending Intent เพิ่มเข้ามาในภายหลัง
ในขณะเดียวกัน นักพัฒนาแต่ละคนก็อาจจะต้องการใช้งาน Pending Intent แบบ Mutable ด้วยเหตุผลบางอย่าง จึงทำให้ระบบแอนดรอยด์บังคับให้ Pending Intent เป็น Immutable ทั้งหมดไม่ได้ และนั่นคือที่มาที่นักพัฒนาต้องกำหนดค่าดังกล่าวด้วยตัวเองยังไงล่ะ
แหล่งข้อมูลอ้างอิง
- Pending intents - Privacy & Security [Android Developers]
- Specify Mutability - Intents and Intent Filters [Android Developers]
- "Having fun with secure messengers and Android Wear and Android Auto" by Artem Chaykin at CanSecWest2016 [SlideShare]
- "Pending Intents: A Pentester’s view" by +Ch0pin🕷️ [Medium]