Danh mục OWASP: MASVS-CODE: Chất lượng mã
Tổng quan
Việc sử dụng PendingIntent.getCreator*()
hoặc PendingIntent.getTarget*()
để xác định xem có nên tin tưởng người gửi PendingIntent hay không sẽ tạo ra nguy cơ khai thác.
PendingIntent.getCreator*()
hoặc PendingIntent.getTarget*()
trả về trình tạo PendingIntent. Trình tạo này không phải lúc nào cũng khớp với người gửi. Nhà sáng tạo có thể đáng tin cậy, nhưng bạn không bao giờ nên tin tưởng người gửi, vì người gửi có thể là một ứng dụng độc hại đã lấy PendingIntent của một ứng dụng khác bằng nhiều cơ chế, ví dụ:
- từ
NotificationListenerService
- các trường hợp sử dụng hợp lệ thuộc ứng dụng dễ bị tấn công.
Ví dụ về trường hợp sử dụng hợp lệ PendingIntent.getCreator*()
hoặc PendingIntent.getTarget*()
là để hiện biểu tượng của ứng dụng sẽ được PendingIntent khởi động.
Tác động
Việc tin tưởng người gửi PendingIntent vì bạn đã truy vấn (và tin tưởng) nhà sáng tạo có thể dẫn đến các lỗ hổng. Nếu một ứng dụng tin tưởng người gửi PendingIntent dựa trên người tạo của ứng dụng đó, rồi chia sẻ logic xác thực hoặc uỷ quyền, thì bất cứ khi nào người gửi PendingIntent là một ứng dụng độc hại, điều này sẽ dẫn đến việc bỏ qua quy trình xác thực hoặc thậm chí có thể thực thi mã từ xa dựa trên đầu vào không hợp lệ, không đáng tin cậy, tuỳ thuộc vào việc triển khai mã của ứng dụng dễ bị tấn công.
Giải pháp giảm thiểu
Phân biệt người gửi và nhà sáng tạo
Mọi loại logic xác thực hoặc uỷ quyền được thực hiện khi nhận PendingIntent đều không được dựa trên các giả định liên quan đến người tạo PendingIntent được xác định bằng cách sử dụng PendingIntent.getCreator*()
hoặc PendingIntent.getTarget*()
.
Sử dụng các cách thay thế để xác thực người gọi
Nếu cần xác thực người gọi, thay vì dùng PendingIntent, bạn nên dùng Service hoặc ContentProvider – cả hai đều cho phép tìm nạp UID của người gọi bằng Binder.getCallingUid() khi bạn đang trong bối cảnh gửi một IPC đến. Bạn có thể truy vấn UID sau bằng cách sử dụng PackageManager.getPackagesForUid().
Một phương pháp khác (có từ API cấp 34) là sử dụng BroadcastReceiver.getSentFromUid() hoặc BroadcastReceiver.getSentFromPackage() nếu người gửi chọn chia sẻ danh tính trong quá trình truyền tin bằng BroadcastOptions.isShareIdentityEnabled().
Bạn phải luôn kiểm tra xem gói gọi có chữ ký dự kiến hay không, vì các gói được tải lên từ bên ngoài có thể có tên gói trùng lặp với tên gói trên Cửa hàng Play.