不安全的反序列化
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
OWASP 类别:MASVS-CODE:代码质量
概览
在存储或传输大量 Java 对象数据时,通常更高效的做法是先序列化数据。然后,数据将由接收应用、activity 或提供程序进行反序列化过程,最终处理数据。在正常情况下,系统会序列化数据,然后再反序列化,而无需用户干预。不过,反序列化进程与其预期对象之间的信任关系可能会被恶意攻击者滥用,例如,他们可能会拦截和修改序列化对象。这会使恶意行为者能够执行拒绝服务 (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)。
这些类型的攻击可能比较轻微。例如,应用可能包含仅需要一个参数的 intent,该参数在经过验证后将被反序列化。如果攻击者将第二个意外的恶意 extra 参数与预期的 extra 参数一起发送,这将导致注入的所有数据对象被反序列化,因为 intent 会将 extra 视为 Bundle
。恶意用户可能会利用此行为注入对象数据,这些数据在反序列化后可能会导致 RCE、数据泄露或丢失。
最佳实践是假定所有序列化数据不可信且可能具有恶意。为确保序列化数据的完整性,请对数据执行验证检查,确保其是应用预期的正确类和格式。
一个可行的解决方案是,为 java.io.ObjectInputStream
库实现预测模式。通过修改负责反序列化的代码,您可以确保在 intent 中仅反序列化明确指定的一组类。
从 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 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-07-26。
[null,null,["最后更新时间 (UTC):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)"]]