不安全的反序列化程序
透過集合功能整理內容
你可以依據偏好儲存及分類內容。
OWASP 類別:MASVS-CODE:程式碼品質
總覽
當您要儲存或傳輸大量 Java 物件資料時,通常會先將資料序列化,以便提高效率。接著,資料接收端應用程式、活動或最終處理資料的供應器就會執行去序列化程序。在一般情況下,資料會先經過序列化再還原序列化,而沒有任何使用者介入處理。不過,惡意人士可能會濫用序列化程序與其預期物件之間的信任關係,例如攔截及變更序列化物件。這會讓惡意行為人能夠執行攻擊,例如阻斷服務 (DoS)、權限提升和遠端程式碼執行 (RCE)。
雖然 Serializable
類別是用於管理序列化的常用方法,但 Android 也有專門用於處理序列化的類別,稱為 Parcel
。使用 Parcel
類別,物件資料可序列化為位元組串流資料,並使用 Parcelable
介面封裝至 Parcel
。這樣可提升 Parcel
的傳輸或儲存效率。
不過,使用 Parcel
類別時,請務必謹慎考量,因為該類別是高效率的 IPC 傳輸機制,但不應用於在本機持續性儲存空間中儲存序列化物件,否則可能會導致資料相容性問題或資料遺失。需要讀取資料時,Parcelable
介面可用於將 Parcel
還原序列化,並將其還原為物件資料。
在 Android 中,有三種主要的途徑可用於利用反序列化:
- 利用開發人員的錯誤假設,從自訂類別類型還原序列化物件作業可以安全。實際上,任何類別來源的物件都可能會被惡意內容取代,在最糟的情況下,這可能會干擾相同或其他應用程式的類別載入器。這種幹擾行為採用插入危險值的方式,例如根據類別用途插入這類值可能導致資料竊取或帳戶盜用。
- 利用設計上被視為不安全的反序列舉方法 (例如 CVE-2023-35669,這是一個本機權限提升缺陷,可透過深層連結反序列舉向量注入任意 JavaScript 程式碼)
- 利用應用程式邏輯的缺陷 (例如 CVE-2023-20963:本機權限提升漏洞可讓應用程式在 Android 的 WorkSource Parcel 邏輯中,在具有特殊權限的環境中下載及執行程式碼)。
影響
任何會將不受信任或惡意的序列化資料反序列化的應用程式,都可能遭受遠端程式碼執行或拒絕服務攻擊。
攻擊者可以利用應用程式邏輯中缺少包裹驗證程序的手法,插入任意物件。在去序列化後,可能會強制要求應用程式執行惡意程式碼,進而導致阻斷服務 (DoS)、權限提升和遠端程式碼執行 (RCE)。
這類攻擊可能難以察覺。舉例來說,應用程式可能包含只預期一個參數的意圖,該參數在經過驗證後會進行反序化。如果攻擊者除了預期的參數外,還傳送第二個意料之外的惡意額外參數,這會導致所有注入的資料物件遭到反序列化,因為意圖會將額外參數視為 Bundle
。惡意使用者可能會利用這項行為,插入物件資料,一旦經過反序列化,可能會導致 RCE、資料外洩或資料遺失。
最佳做法是假設所有序列化資料皆不受信任,且可能含有惡意內容。為確保序列化資料的完整性,請對資料執行驗證檢查,確保資料是應用程式預期的正確類別和格式。
可行的解決方案是為 java.io.ObjectInputStream
程式庫實作前瞻模式。透過修改負責去序列化的程式碼,您可以確保意圖中「只有一組明確指定的類別組合」會去序列化。
自 Android 13 (API 級別 33) 起,Intent
類別內已更新了幾種方法,這些方法可取代舊版 (現已淘汰) 的處理包裝函式,提供更安全的替代方案。這些新的類型安全方法 (例如 getParcelableExtra(java.lang.String, java.lang.Class)
和 getParcelableArrayListExtra(java.lang.String, java.lang.Class)
) 會執行資料類型檢查,找出可能導致應用程式當機的不相符弱點,並可能遭到利用來執行權限提升攻擊,例如 CVE-2021-0928。
以下範例說明如何實作安全版本的 Parcel
類別:
假設 UserParcelable
類別實作 Parcelable
,並建立使用者資料的例項,然後寫入 Parcel
。接著,您可以使用以下 readParcelable
的類型安全的方法讀取序列化的包裹:
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);
請注意,在上述 Java 範例中,方法內使用了 UserParcelable.CREATOR
。這個必要參數會告知 readParcelable
方法預期的類型,且效能優於已淘汰的 readParcelable
方法。
特定風險
本節列舉必須採用非標準因應策略或在特定 SDK 層級進行因應的風險,並提供相關完整資訊。
風險:不必要的物件去序列化
在類別中實作 Serializable
介面會自動造成指定類別的所有子類型實作介面。在這種情況下,部分物件可能會繼承上述介面,也就是說,系統仍會處理未經過序列化處理的特定物件。這可能會不經意地增加攻擊面。
因應措施
如果類別繼承 Serializable
介面,則應根據 OWASP 指南實作 readObject
方法,以免類別中的一組物件可進行反序列化:
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");
}
資源
這個頁面中的內容和程式碼範例均受《內容授權》中的授權所規範。Java 與 OpenJDK 是 Oracle 和/或其關係企業的商標或註冊商標。
上次更新時間:2025-07-26 (世界標準時間)。
[[["容易理解","easyToUnderstand","thumb-up"],["確實解決了我的問題","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["缺少我需要的資訊","missingTheInformationINeed","thumb-down"],["過於複雜/步驟過多","tooComplicatedTooManySteps","thumb-down"],["過時","outOfDate","thumb-down"],["翻譯問題","translationIssue","thumb-down"],["示例/程式碼問題","samplesCodeIssue","thumb-down"],["其他","otherDown","thumb-down"]],["上次更新時間:2025-07-26 (世界標準時間)。"],[],[],null,["# Unsafe Deserialization\n\n\u003cbr /\u003e\n\n**OWASP category:** [MASVS-CODE: Code Quality](https://mas.owasp.org/MASVS/10-MASVS-CODE)\n\nOverview\n--------\n\nWhen storing or transferring large amounts of Java object data, it is often more\nefficient to serialize the data first. The data will then undergo a\ndeserialization process by the receiving application, activity, or provider that\nends up handling the data. Under normal circumstances, data is serialized and\nthen deserialized without any user intervention. However, the trust relationship\nbetween the deserialization process and its intended object can be abused by a\nmalicious actor who could, for example, intercept and alter serialized objects.\nThis would enable the malicious actor to perform attacks such as denial of\nservice (DoS), privilege escalation, and remote code execution (RCE).\n\nWhile the [`Serializable`](/reference/java/io/Serializable) class is a common method for managing\nserialization, Android has its own class for handling serialization called\n[`Parcel`](/reference/android/os/Parcel). Using the `Parcel` class, object data can be serialized into byte\nstream data and packed into a `Parcel` using the [`Parcelable`](/reference/android/os/Parcelable) interface.\nThis allows the `Parcel` to be transported or stored more efficiently.\n\nNevertheless, careful consideration should be given when using the `Parcel`\nclass, as it is meant to be a high-efficiency IPC transport mechanism, but\nshouldn't be used to store serialized objects within the local persistent\nstorage as this could lead to data compatibility issues or loss. When the data\nneeds to be read, the `Parcelable` interface can be used to deserialize the\n`Parcel` and turn it back into object data.\n\nThere are three primary vectors for exploiting deserialization in Android:\n\n- Taking advantage of a developer's incorrect assumption that deserializing objects proceeding from a custom class type is safe. In reality, any object sourced by any class can be potentially replaced with malicious content that, in the worst case scenario, can interfere with the same or other applications' class loaders. This interference takes the form of injecting dangerous values that, according to the class purpose, may lead, for example, to data exfiltration or account takeover.\n- Exploiting deserialization methods that are considered unsafe by design (for example [CVE-2023-35669](https://cve.mitre.org/cgi-bin/cvename.cgi?name=2023-35669), a local privilege escalation flaw that allowed arbitrary JavaScript code injection through a deep-link deserialization vector)\n- Exploiting flaws in the application logic (for example [CVE-2023-20963](https://nvd.nist.gov/vuln/detail/CVE-2023-20963), a local privilege escalation flaw that allowed an app to download and execute code within a privileged environment through a flaw within Android's WorkSource parcel logic).\n\nImpact\n------\n\nAny application that deserializes untrusted or malicious serialized data could\nbe vulnerable to remote code execution or denial of service attacks.\n\nRisk: Deserialization of untrusted input\n----------------------------------------\n\nAn attacker can exploit the lack of parcel verification within the application\nlogic in order to inject arbitrary objects that, once deserialized, could force\nthe application to execute malicious code that may result in denial of service\n(DoS), privilege escalation, and remote code execution (RCE).\n\nThese types of attacks may be subtle. For example, an application may contain an\nintent expecting only one parameter that, after being validated, will be\ndeserialized. If an attacker sends a second, unexpected malicious extra\nparameter along with the expected one, this will cause all the data objects\ninjected to be deserialized since the intent treats the extras as a\n[`Bundle`](/reference/android/os/Bundle). A malicious user may make use of this behavior to inject object\ndata that, once deserialized, may lead to RCE, data compromise, or loss.\n\n### Mitigations\n\nAs a best practice, assume that all serialized data is untrusted and potentially\nmalicious. To ensure the integrity of serialized data, perform verification\nchecks on the data to make sure it's the correct class and format expected by\nthe application.\n\nA feasible solution could be to implement the look-ahead pattern for the\n`java.io.ObjectInputStream` [library](/reference/java/io/ObjectInputStream). By modifying the code responsible for\ndeserialization, you can make sure that [only an explicitly specified set of\nclasses](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html#harden-your-own-javaioobjectinputstream) is deserialized within the intent.\n\nAs of Android 13 (API level 33), several methods have been updated within the\n`Intent` class that are considered safer alternatives to older and\nnow-deprecated methods for handling parcels. These new type-safer methods, such\nas [`getParcelableExtra(java.lang.String, java.lang.Class)`](/reference/android/content/Intent#getParcelableExtra(java.lang.String,%20java.lang.Class%3CT%3E)) and\n[`getParcelableArrayListExtra(java.lang.String, java.lang.Class)`](/reference/android/content/Intent#getParcelableArrayListExtra(java.lang.String,%20java.lang.Class%3C?%20extends%20T%3E)) perform\ndata type checks to catch mismatch weaknesses that might cause applications to\ncrash and potentially be exploited to perform privilege escalation attacks, such\nas [CVE-2021-0928](https://nvd.nist.gov/vuln/detail/CVE-2021-0928).\n\nThe following example demonstrates how a safe version of the `Parcel` class\ncould be implemented:\n\nSuppose the class `UserParcelable` implements `Parcelable` and creates an\ninstance of user data that's then written to a `Parcel`. The following\ntype-safer method of [`readParcelable`](/reference/android/os/Parcel#readParcelable(java.lang.ClassLoader,%20java.lang.Class%3CT%3E)) could then be used to read the\nserialized parcel: \n\n### Kotlin\n\n val parcel = Parcel.obtain()\n val userParcelable = parcel.readParcelable(UserParcelable::class.java.classLoader)\n\n### Java\n\n Parcel parcel = Parcel.obtain();\n UserParcelable userParcelable = parcel.readParcelable(UserParcelable.class, UserParcelable.CREATOR);\n\nNotice in the Java example above the use of `UserParcelable.CREATOR` within the\nmethod. This required parameter tells the `readParcelable` method what type to\nexpect and is more performant than the now-deprecated version of the\n`readParcelable` method.\n\nSpecific Risks\n--------------\n\nThis section gathers risks that require non-standard mitigation strategies or\nwere mitigated at certain SDK level and are here for completeness.\n\n### Risk: Unwanted Object Deserialization\n\nImplementing the `Serializable` interface within a class will automatically\ncause all subtypes of the given class to implement the interface. In this\nscenario, some objects may inherit the aforementioned interface, meaning\nspecific objects that are not meant to be deserialized will still be processed.\nThis can inadvertently increase the attack surface.\n\n#### Mitigations\n\nIf a class inherits the `Serializable` interface, as per [OWASP guidance](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html#prevent-deserialization-of-domain-objects), the `readObject` method should be implemented as follows in order to\navoid that a set of objects in the class can be deserialized: \n\n### Kotlin\n\n @Throws(IOException::class)\n private final fun readObject(in: ObjectInputStream) {\n throw IOException(\"Cannot be deserialized\")\n }\n\n### Java\n\n private final void readObject(ObjectInputStream in) throws java.io.IOException {\n throw new java.io.IOException(\"Cannot be deserialized\");\n }\n\nResources\n---------\n\n- [Parcelables](/reference/android/os/Parcel#parcelables)\n- [Parcel](/reference/android/os/Parcel)\n- [Serializable](/reference/java/io/Serializable)\n- [Intent](/reference/android/content/Intent)\n- [Android Deserialization Vulnerabilities: A Brief history](https://securitylab.github.com/research/android-deserialization-vulnerabilities/)\n- [Android Parcels: The Bad, the Good and the Better (video)](https://www.youtube.com/watch?v=qIzMKfOmIAA)\n- [Android Parcels: The Bad, the Good and the Better (presentation slides)](https://i.blackhat.com/EU-22/Wednesday-Briefings/EU-22-Ke-Android-Parcels-Introducing-Android-Safer-Parcel.pdf)\n- [CVE-2014-7911: Android \\\u003c5.0 Privilege Escalation using ObjectInputStream](https://seclists.org/fulldisclosure/2014/Nov/51)\n- [CVE-CVE-2017-0412](https://bugs.chromium.org/p/project-zero/issues/detail?id=1002)\n- [CVE-2021-0928: Parcel Serialization/Deserialization Mismatch](https://nvd.nist.gov/vuln/detail/CVE-2021-0928)\n- [OWASP guidance](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html#prevent-deserialization-of-domain-objects)"]]