الحذف غير الآمن
تنظيم صفحاتك في مجموعات
يمكنك حفظ المحتوى وتصنيفه حسب إعداداتك المفضّلة.
فئة OWASP: MASVS-CODE: جودة الرموز البرمجية
نظرة عامة
عند تخزين كميات كبيرة من بيانات عناصر Java أو نقلها، غالبًا ما يكون التنسيق التسلسلي للبيانات أكثر فعالية أولاً. ستخضع البيانات بعد ذلك ل عملية رمزي عكسي من خلال التطبيق أو النشاط أو مقدّم الخدمة المستلِم الذي
ينتهي به الأمر بمعالجة البيانات. في الظروف العادية، يتم تسلسل البيانات ثم تحويلها إلى سلسلة بدون أي تدخل من المستخدم. ومع ذلك، يمكن أن يساء استخدام علاقة الثقة
بين عملية إزالة التسلسل والعنصر المقصود من قِبل أحد
الجهات الفاعلة الخبيثة التي يمكنها، على سبيل المثال، اعتراض العناصر التي تم تسلسلها وتغييرها.
وقد يتيح ذلك للجهة الضارّة تنفيذ هجمات مثل رفض الخدمة (DoS) وتصعيد الامتيازات وتنفيذ الرموز البرمجية عن بُعد (RCE).
على الرغم من أنّ فئة Serializable
هي طريقة شائعة لإدارة
التسلسل، فإنّ Android لديه فئة خاصة به لمعالجة التسلسل تُسمى
Parcel
. باستخدام فئة Parcel
، يمكن تسلسل بيانات الكائنات إلى بيانات بث ملف شخصي وتعبئتها في Parcel
باستخدام واجهة Parcelable
.
ويتيح ذلك نقل "Parcel
" أو تخزينها بكفاءة أكبر.
ومع ذلك، يجب التفكير بعناية عند استخدام فئة Parcel
، لأنّها مخصّصة لتكون آلية نقل عالية الكفاءة لبروتوكول IPC، ولكن ينبغي عدم استخدامها لتخزين العناصر التسلسلية ضمن التخزين الدائم المحلي، لأنّ ذلك قد يؤدي إلى مشاكل في توافق البيانات أو فقدانها. عند الحاجة إلى قراءة البيانات، يمكن استخدام واجهة Parcelable
لتحويل Parcel
إلى تنسيق ثنائي وتحويله مرة أخرى إلى بيانات عنصر.
هناك ثلاث طرق رئيسية لاستغلال ميزة تحويل البيانات إلى تنسيق قابل للقراءة في Android:
- الاستفادة من افتراض المطوّر غير الصحيح بأنّ فك ترميز
العناصر التي تأتي من نوع فئة مخصّصة آمن في الواقع، يمكن استبدال أي عنصر
يستخدِمه أي فئة بمحتوى ضار يمكنه، في
أسوأ السيناريوهات، التدخل في أداة تحميل الفئات في التطبيقات نفسها أو التطبيقات الأخرى. ويأخذ هذا التدخل شكل إدخال قيم خطيرة
قد تؤدي، وفقًا لهدف الفئة، إلى مثلاً exfiltration data أو الاستيلاء على الحساب.
- استغلال طُرق تحويل البيانات إلى سلسلة أحرف يُعتبَر أنّها غير آمنة من حيث التصميم (مثل CVE-2023-35669، وهي ثغرة أمنية في تصعيد الأذونات المحلية تسمح بدمج رمز JavaScript عشوائي من خلال ناقلات تحويل البيانات إلى سلسلة أحرف لرابط لصفحة في التطبيق)
- الاستفادة من العيوب في منطق التطبيقات (على سبيل المثال، CVE-2023-20963، وهو خلل في تصعيد الامتيازات المحلية أتاح للتطبيق تنزيل رمز برمجي وتنفيذه في بيئة محمية من خلال عيب في منطق حزم WorkSource في Android).
التأثير
أي تطبيق يُعيد تسلسل البيانات غير الموثوق بها أو الضارّة قد
يكون عرضة لهجوم تنفيذ رمز برمجي عن بُعد أو هجوم حجب الخدمة.
يمكن للمهاجم استغلال عدم التحقق من قطعة الأراضي ضمن منطق التطبيق من أجل إدخال كائنات عشوائية قد تجبر التطبيق، بعد إلغاء تسلسله، على تنفيذ رمز ضار قد يؤدي إلى رفض الخدمة (DoS)، وتصعيد الامتيازات، وتنفيذ الرمز عن بعد (RCE).
قد تكون هذه الأنواع من الهجمات خفية. على سبيل المثال، قد يحتوي تطبيق على نية تتوقع فيها معلَمة واحدة فقط، وسيتم إلغاء تسلسلها بعد التحقّق من صحتها. إذا أرسل مهاجم مَعلمة إضافية ثانية ضارة وغير متوقّعة مع المَعلمة المتوقّعة، سيؤدي ذلك إلى إعادة تسلسل جميع عناصر البيانات التي تم إدخالها لأنّ النية تتعامل مع البيانات الإضافية على أنّها Bundle
. يمكن أن يستغل مستخدم ضار هذا السلوك لحقن بيانات
العناصر التي قد تؤدي إلى تنفيذ رموز ضارة أو اختراق البيانات أو فقدانها بعد إعادة تسلسلها.
كإحدى أفضل الممارسات، افترض أن جميع البيانات المتسلسلة غير موثوق بها وربما تكون ضارة. لضمان سلامة البيانات التسلسلية، عليك إجراء عمليات التحقّق
من البيانات للتأكّد من أنّها من الفئة والتنسيق الصحيحَين المتوقّعَين من
التطبيق.
يمكن أن يكون الحلّ المُجدي هو تطبيق نمط البحث عن المحتوى التالي في
java.io.ObjectInputStream
المكتبة. من خلال تعديل الرمز البرمجي المسؤول عن
ترميز البيانات، يمكنك التأكّد من أنّه يتم ترميز مجموعة محدّدة بوضوح من
الفئات فقط ضمن الطلب.
اعتبارًا من Android 13 (المستوى 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)"]]