الحذف غير الآمن

فئة 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");
}

المراجع