Danh mục OWASP: MASVS-CODE: Chất lượng mã
Tổng quan
Khi lưu trữ hoặc chuyển một lượng lớn dữ liệu đối tượng Java, bạn nên chuyển đổi tuần tự dữ liệu trước để đạt được hiệu quả cao hơn. Sau đó, dữ liệu sẽ trải qua quá trình huỷ chuyển đổi tuần tự bởi ứng dụng nhận, hoạt động hoặc trình cung cấp sẽ xử lý dữ liệu đó. Trong trường hợp bình thường, dữ liệu được chuyển đổi tuần tự rồi chuyển đổi tuần tự mà không cần người dùng can thiệp. Tuy nhiên, mối quan hệ tin cậy giữa quá trình huỷ chuyển đổi tuần tự và đối tượng dự định có thể bị một tác nhân độc hại lợi dụng, chẳng hạn như chặn và thay đổi các đối tượng đã chuyển đổi tuần tự. Điều này sẽ cho phép kẻ tấn công thực hiện các cuộc tấn công như từ chối dịch vụ (DoS), nâng cấp đặc quyền và thực thi mã từ xa (RCE).
Mặc dù lớp Serializable
là một phương thức phổ biến để quản lý quá trình chuyển đổi tuần tự, nhưng Android có lớp riêng để xử lý quá trình chuyển đổi tuần tự có tên là Parcel
. Bằng cách sử dụng lớp Parcel
, dữ liệu đối tượng có thể được chuyển đổi tuần tự thành dữ liệu luồng byte và được đóng gói vào Parcel
bằng giao diện Parcelable
.
Điều này cho phép vận chuyển hoặc lưu trữ Parcel
hiệu quả hơn.
Tuy nhiên, bạn nên cân nhắc kỹ khi sử dụng lớp Parcel
, vì đây là cơ chế truyền tải IPC hiệu quả cao. Bạn không nên dùng lớp này để lưu trữ các đối tượng được chuyển đổi tuần tự trong bộ nhớ cục bộ liên tục vì điều này có thể dẫn đến các vấn đề về khả năng tương thích hoặc mất khả năng tương thích dữ liệu. Khi cần đọc dữ liệu, bạn có thể sử dụng giao diện Parcelable
để chuyển đổi tuần tự Parcel
và chuyển đổi lại thành dữ liệu đối tượng.
Có ba vectơ chính để khai thác việc giải mã tuần tự trong Android:
- Lợi dụng giả định không chính xác của nhà phát triển rằng việc chuyển đổi tuần tự các đối tượng từ một loại lớp tuỳ chỉnh là an toàn. Trong thực tế, bất kỳ đối tượng nào do lớp nào cung cấp cũng có thể được thay thế bằng nội dung độc hại. Trong trường hợp xấu nhất, nội dung này có thể can thiệp vào trình tải lớp của chính lớp đó hoặc các ứng dụng khác. Hành vi can thiệp này diễn ra dưới dạng chèn các giá trị nguy hiểm. Theo mục đích của lớp, hành vi này có thể dẫn đến việc đánh cắp dữ liệu hoặc chiếm đoạt tài khoản.
- Khai thác các phương thức chuyển đổi tuần tự được coi là không an toàn theo thiết kế (ví dụ: CVE-2023-35669, một lỗi nâng cấp đặc quyền cục bộ cho phép chèn mã JavaScript tuỳ ý thông qua vectơ chuyển đổi tuần tự đường liên kết sâu)
- Khai thác các lỗ hổng trong logic ứng dụng (ví dụ: CVE-2023-20963, một lỗ hổng nâng cấp đặc quyền cục bộ cho phép ứng dụng tải xuống và thực thi mã trong một môi trường đặc quyền thông qua một lỗ hổng trong logic gói WorkSource của Android).
Tác động
Bất kỳ ứng dụng nào giải mã tuần tự dữ liệu không đáng tin cậy hoặc dữ liệu tuần tự độc hại đều có thể dễ bị tấn công thực thi mã từ xa hoặc từ chối dịch vụ.
Rủi ro: Huỷ chuyển đổi tuần tự dữ liệu đầu vào không đáng tin cậy
Kẻ tấn công có thể khai thác tình trạng thiếu xác minh gói trong logic ứng dụng để chèn các đối tượng tuỳ ý mà sau khi được giải tuần tự, có thể buộc ứng dụng thực thi mã độc hại có thể dẫn đến tình trạng từ chối dịch vụ (DoS), chuyển lên cấp đặc quyền và thực thi mã từ xa (RCE).
Những kiểu tấn công này có thể khó phát hiện. Ví dụ: một ứng dụng có thể chứa một ý định chỉ dự kiến một thông số, sau khi được xác thực, sẽ được chuyển đổi tuần tự. Nếu kẻ tấn công gửi một tham số bổ sung độc hại thứ hai, không mong muốn cùng với tham số dự kiến, thì điều này sẽ khiến tất cả các đối tượng dữ liệu được chèn sẽ được chuyển đổi tuần tự vì ý định coi các tham số bổ sung này là Bundle
. Người dùng độc hại có thể lợi dụng hành vi này để chèn dữ liệu đối tượng. Sau khi được chuyển đổi tuần tự, hành vi này có thể dẫn đến RCE, xâm phạm hoặc mất dữ liệu.
Giải pháp giảm thiểu
Tốt nhất là bạn nên giả định rằng tất cả dữ liệu được chuyển đổi tuần tự đều không đáng tin cậy và có thể xấu tính. Để đảm bảo tính toàn vẹn của dữ liệu tuần tự, hãy thực hiện các bước kiểm tra xác minh trên dữ liệu để đảm bảo đó là lớp và định dạng chính xác mà ứng dụng dự kiến.
Một giải pháp khả thi có thể là triển khai mẫu xem trước cho thư viện java.io.ObjectInputStream
. Bằng cách sửa đổi mã chịu trách nhiệm về việc giải mã tuần tự, bạn có thể đảm bảo rằng chỉ một tập hợp các lớp được chỉ định rõ ràng mới được giải mã tuần tự trong ý định.
Kể từ Android 13 (API cấp 33), một số phương thức đã được cập nhật trong lớp Intent
. Những phương thức này được xem là lựa chọn thay thế an toàn hơn so với các phương thức cũ và hiện không còn được dùng để xử lý các gói. Các phương thức mới an toàn hơn về loại này, chẳng hạn như getParcelableExtra(java.lang.String, java.lang.Class)
và getParcelableArrayListExtra(java.lang.String, java.lang.Class)
, thực hiện các bước kiểm tra loại dữ liệu để phát hiện các điểm yếu không khớp có thể khiến ứng dụng gặp sự cố và có thể bị khai thác để thực hiện các cuộc tấn công nâng cấp đặc quyền, chẳng hạn như CVE-2021-0928.
Ví dụ sau đây minh hoạ cách triển khai phiên bản an toàn của lớp Parcel
:
Giả sử lớp UserParcelable
triển khai Parcelable
và tạo một thực thể của dữ liệu người dùng, sau đó được ghi vào Parcel
. Sau đó, bạn có thể sử dụng phương thức an toàn hơn về loại của readParcelable
để đọc gói đã chuyển đổi tuần tự:
Kotlin
val parcel = Parcel.obtain()
val userParcelable = parcel.readParcelable(UserParcelable::class.java.classLoader)
Java
Parcel parcel = Parcel.obtain();
UserParcelable userParcelable = parcel.readParcelable(UserParcelable.class, UserParcelable.CREATOR);
Lưu ý trong ví dụ Java ở trên về việc sử dụng UserParcelable.CREATOR
trong phương thức. Tham số bắt buộc này cho phương thức readParcelable
biết loại dữ liệu cần dự kiến và có hiệu suất cao hơn phiên bản hiện không dùng nữa của phương thức readParcelable
.
Rủi ro cụ thể
Phần này tổng hợp các rủi ro đòi hỏi chiến lược giảm thiểu không theo chuẩn hoặc được giảm thiểu ở một số cấp độ SDK nhất định và được liệt kê ở đây chỉ để cho đủ.
Rủi ro: Quá trình huỷ chuyển đổi tuần tự đối tượng không mong muốn
Việc triển khai giao diện Serializable
trong một lớp sẽ tự động khiến tất cả các loại phụ của lớp nhất định triển khai giao diện này. Trong trường hợp này, một số đối tượng có thể kế thừa giao diện nêu trên, nghĩa là các đối tượng cụ thể không được chuyển đổi tuần tự vẫn sẽ được xử lý.
Điều này có thể vô tình làm tăng bề mặt tấn công.
Giải pháp giảm thiểu
Nếu một lớp kế thừa giao diện Serializable
, theo hướng dẫn của OWASP, bạn nên triển khai phương thức readObject
như sau để tránh việc một tập hợp đối tượng trong lớp có thể được chuyển đổi tuần tự:
Kotlin
@Throws(IOException::class)
private final fun readObject(in: ObjectInputStream) {
throw IOException("Cannot be deserialized")
}
Java
private final void readObject(ObjectInputStream in) throws java.io.IOException {
throw new java.io.IOException("Cannot be deserialized");
}
Tài nguyên
- Parcelables
- Gói
- Serializable
- Intent
- Lỗ hổng huỷ chuyển đổi tuần tự trên Android: Sơ lược về các lỗ hổng bảo mật
- Android Parcels: The Bad, the Good and the Better (video)
- Android Parcels: The Bad, the Good and the Better (bản trình bày dạng trang trình bày)
- CVE-2014-7911: Nâng cấp đặc quyền trên Android <5.0 bằng ObjectInputStream
- CVE-CVE-2017-0412
- CVE-2021-0928: Không khớp quá trình chuyển đổi tuần tự/huỷ chuyển đổi tuần tự gói
- Hướng dẫn của OWASP