آب زدایی ناامن

دسته OWASP: MASVS-CODE: کیفیت کد

نمای کلی

هنگام ذخیره یا انتقال مقادیر زیادی از داده های شی جاوا، اغلب کارآمدتر است که ابتدا داده ها را سریال کنید. سپس داده‌ها توسط برنامه، فعالیت یا ارائه‌دهنده دریافت‌کننده که به مدیریت داده‌ها ختم می‌شود، تحت یک فرآیند سریال‌زدایی قرار می‌گیرد. در شرایط عادی، داده‌ها سریال‌سازی می‌شوند و سپس بدون دخالت کاربر، سریال‌سازی می‌شوند. با این حال، رابطه اعتماد بین فرآیند سریال‌زدایی و هدف مورد نظر آن می‌تواند توسط یک عامل مخرب که می‌تواند، برای مثال، اشیاء سریال‌سازی‌شده را رهگیری و تغییر دهد، مورد سوء استفاده قرار گیرد. این عامل مخرب را قادر می سازد تا حملاتی مانند انکار سرویس (DoS)، افزایش امتیاز و اجرای کد از راه دور (RCE) را انجام دهد.

در حالی که کلاس Serializable یک روش متداول برای مدیریت سریال‌سازی است، اندروید کلاس مخصوص به خود را برای مدیریت سریال‌سازی به نام Parcel دارد. با استفاده از کلاس Parcel ، داده های شی را می توان در داده های جریان بایت سریال کرد و با استفاده از رابط Parcelable در یک Parcel بسته بندی کرد. این اجازه می دهد تا Parcel به طور موثرتری حمل و یا ذخیره شود.

با این وجود، هنگام استفاده از کلاس Parcel باید به دقت مورد توجه قرار گیرد، زیرا قرار است مکانیزم انتقال IPC با کارایی بالا باشد، اما نباید برای ذخیره اشیاء سریالی در حافظه محلی دائمی استفاده شود زیرا این امر می‌تواند منجر به مشکلات سازگاری داده شود. یا از دست دادن هنگامی که داده ها نیاز به خواندن دارند، می توان از رابط Parcelable برای Parcel و تبدیل آن به داده های شیء استفاده کرد.

سه بردار اصلی برای استفاده از deserialization در اندروید وجود دارد:

  • استفاده از فرضیه نادرست یک توسعه دهنده مبنی بر اینکه deserializing اشیاء از یک نوع کلاس سفارشی ایمن است. در واقع، هر شیئی که توسط هر کلاسی منبع می‌شود، می‌تواند به طور بالقوه با محتوای مخرب جایگزین شود که در بدترین حالت، می‌تواند با بارگذارهای کلاس مشابه یا سایر برنامه‌ها تداخل داشته باشد. این تداخل به شکل تزریق مقادیر خطرناکی است که با توجه به هدف کلاس، ممکن است به عنوان مثال منجر به استخراج داده یا تصاحب حساب شود.
  • بهره‌برداری از روش‌های deserialization که از نظر طراحی ناامن تلقی می‌شوند (برای مثال CVE-2023-35669 ، یک نقص افزایش امتیاز محلی که امکان تزریق کد جاوا اسکریپت دلخواه را از طریق یک بردار deserialization عمیق پیوند می‌دهد)
  • بهره‌برداری از نقص‌های منطق برنامه (برای مثال CVE-2023-20963 ، یک نقص افزایش امتیاز محلی که به برنامه اجازه می‌دهد کد را در یک محیط ممتاز از طریق یک نقص در منطق بسته‌های WorkSource Android بارگیری و اجرا کند).

تاثیر

هر برنامه‌ای که داده‌های سریالی نامعتبر یا مخرب را سریال‌سازی می‌کند، می‌تواند در برابر اجرای کد از راه دور یا حملات انکار سرویس آسیب‌پذیر باشد.

ریسک: غیراصولی کردن ورودی نامعتبر

یک مهاجم می‌تواند از عدم تأیید بسته در منطق برنامه برای تزریق اشیاء دلخواه استفاده کند که پس از غیرقانونی شدن، می‌تواند برنامه را مجبور به اجرای کد مخرب کند که ممکن است منجر به انکار سرویس (DoS)، افزایش امتیازات و اجرای کد از راه دور شود. (RCE).

این نوع حملات ممکن است ظریف باشند. به عنوان مثال، یک برنامه کاربردی ممکن است حاوی یک هدف باشد که فقط یک پارامتر را انتظار دارد که پس از تأیید اعتبار، از فهرست خارج شود. اگر مهاجم یک پارامتر اضافی مخرب غیرمنتظره و دوم را همراه با پارامتر مورد انتظار ارسال کند، این امر باعث می‌شود که تمام داده‌های تزریق‌شده به‌عنوان یک Bundle رفتار کند. یک کاربر مخرب ممکن است از این رفتار برای تزریق داده های شی استفاده کند که پس از جداسازی، ممکن است منجر به RCE، به خطر افتادن داده یا از دست رفتن شود.

اقدامات کاهشی

به عنوان بهترین روش، فرض کنید که تمام داده های سریالی غیرقابل اعتماد و بالقوه مخرب هستند. برای اطمینان از یکپارچگی داده های سریال، بررسی های تأیید صحت داده ها را انجام دهید تا مطمئن شوید که کلاس و قالب صحیح مورد انتظار برنامه است.

یک راه حل ممکن می تواند پیاده سازی الگوی نگاه به آینده برای کتابخانه java.io.ObjectInputStream باشد. با تغییر کد مسئول deserialization، می‌توانید مطمئن شوید که فقط مجموعه‌ای از کلاس‌ها که به‌صراحت مشخص شده‌اند در intent deserialized شده‌اند.

از 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 برای خواندن بسته‌های سریالی استفاده کرد:

کاتلین

val parcel = Parcel.obtain()
val userParcelable = parcel.readParcelable(UserParcelable::class.java.classLoader)

جاوا

Parcel parcel = Parcel.obtain();
UserParcelable userParcelable = parcel.readParcelable(UserParcelable.class, UserParcelable.CREATOR);

در مثال جاوا در بالا به استفاده از UserParcelable.CREATOR در متد توجه کنید. این پارامتر مورد نیاز به روش readParcelable می گوید که چه نوع مورد انتظاری را داشته باشد و نسبت به نسخه منسوخ شده متد readParcelable عملکرد بیشتری دارد.

ریسک های خاص

این بخش خطراتی را جمع آوری می کند که به استراتژی های کاهش غیر استاندارد نیاز دارند یا در سطح SDK خاصی کاهش یافته اند و برای کامل شدن در اینجا آمده است.

ریسک: Deserialization اشیاء ناخواسته

پیاده سازی اینترفیس Serializable در یک کلاس به طور خودکار باعث می شود تا تمام زیرگروه های کلاس داده شده این رابط را پیاده سازی کنند. در این سناریو، برخی از اشیاء ممکن است واسط فوق الذکر را به ارث ببرند، به این معنی که اشیاء خاصی که قرار نیست از فهرست خارج شوند، همچنان پردازش خواهند شد. این می تواند به طور ناخواسته سطح حمله را افزایش دهد.

اقدامات کاهشی

اگر یک کلاس رابط Serializable را به ارث می برد، طبق دستورالعمل OWASP ، متد readObject باید به صورت زیر پیاده سازی شود تا از اینکه مجموعه ای از اشیاء در کلاس می توانند از سریال خارج شوند جلوگیری شود:

کاتلین

@Throws(IOException::class)
private final fun readObject(in: ObjectInputStream) {
    throw IOException("Cannot be deserialized")
}

جاوا

private final void readObject(ObjectInputStream in) throws java.io.IOException {
    throw new java.io.IOException("Cannot be deserialized");
}

منابع