安全でない逆シリアル化
コレクションでコンテンツを整理
必要に応じて、コンテンツの保存と分類を行います。
OWASP カテゴリ: MASVS-CODE: コード品質
概要
多くの場合、Java オブジェクト データを大量に保存または転送する場合は、最初にデータをシリアル化したほうが効率的です。その後、受信側のアプリ、アクティビティ、またはプロバイダによって、シリアル化解除プロセスが実行され、最終的にデータを処理します。通常、データはユーザーの介入なしにシリアル化され、シリアル化解除されます。ただし、シリアル化解除プロセスとその対象オブジェクト間の信頼関係は、シリアル化されたオブジェクトをインターセプトして変更するなど、悪意のある攻撃者によって悪用される可能性があります。これにより、悪意のある攻撃者がサービス拒否(DoS)、権限昇格、リモートコード実行(RCE)などの攻撃を実行できるようになります。
Serializable
クラスはシリアル化を管理するための一般的なメソッドですが、Android にはシリアル化を処理するための独自のクラス Parcel
があります。Parcel
クラスを使用すると、オブジェクト データをバイト ストリーム データにシリアル化し、Parcelable
インターフェースを使用して Parcel
にパックできます。これにより、Parcel
をより効率的に転送または保存できます。
ただし、Parcel
クラスは高効率の IPC 転送メカニズムとして設計されているため、使用時には慎重に検討する必要があります。ローカル永続ストレージ内にシリアル化されたオブジェクトを保存するために使用すると、データの互換性の問題やデータの損失につながる可能性があります。データを読み取る必要がある場合は、Parcelable
インターフェースを使用して Parcel
を逆シリアル化し、オブジェクト データに戻すことができます。
Android でシリアル化解除を悪用する主なベクトルは 3 つあります。
- カスタム クラス型から続くオブジェクトの逆シリアル化が安全であるという、デベロッパーの誤った前提を悪用します。実際には、任意のクラスから取得された任意のオブジェクトが悪意のあるコンテンツに置き換えられる可能性があり、最悪のシナリオでは、同じアプリまたは他のアプリのクラスローダを妨害する可能性があります。この干渉は、クラスの目的によっては、データの漏洩やアカウント乗っ取りなどにつながる可能性がある危険な値を挿入する形で発生します。
- 設計上安全でないと考えられるシリアル化解除メソッドの悪用(CVE-2023-35669 など。ディープリンクのシリアル化解除ベクトルによる任意の JavaScript コード挿入を許可するローカル権限昇格の欠陥)。
- アプリロジックの欠陥を悪用する(CVE-2023-20963 など。Android の WorkSource の parcel ロジック内の欠陥により、アプリが特権環境内でコードをダウンロードして実行できるローカル権限昇格の欠陥)。
影響
信頼できないデータや悪意のあるシリアル化されたデータをシリアル化解除するアプリケーションは、リモート コード実行攻撃やサービス拒否攻撃の対象となる可能性があります。
攻撃者は、アプリケーション ロジック内での Parcel の検証がないことを利用して、任意のオブジェクトを挿入できます。このオブジェクトは逆シリアル化されると、アプリケーションが悪意のあるコードを強制的に実行し、サービス拒否(DoS)、権限昇格、リモートコード実行(RCE)につながる可能性があります。
この種の攻撃は軽微である可能性があります。たとえば、アプリに、検証後にシリアル化解除されるパラメータを 1 つだけ想定するインテントを含めることができます。攻撃者が想定されるエクストラ パラメータとともに、予期しない 2 つ目の悪意のあるエクストラ パラメータを送信すると、インテントがエクストラを 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 UTC。
[[["わかりやすい","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 UTC。"],[],[],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)"]]