پرش به محتوای اصلی
آسیب‌پذیری‌های سایت

Insecure Deserialization چیست؟ بررسی ناامن بودن پردازش داده‌های سریال‌شده

Insecure Deserialization یا Deserialization ناامن زمانی رخ می‌دهد که یک برنامه داده سریال‌شده غیرقابل‌اعتماد را بدون بررسی کافی به Object داخلی تبدیل کند. این ضعف می‌تواند باعث دستکاری وضعیت برنامه، دور زدن منطق و کنترل دسترسی، مصرف منابع و در برخی محیط‌ها اجرای کد شود. جلوگیری از Deserialization داده غیرقابل‌اعتماد، استفاده از JSON و DTO، بررسی Integrity با HMAC یا امضا، محدود کردن Typeها و اجرای برنامه با Least Privilege از مهم‌ترین روش‌های مقابله با Insecure Deserialization هستند.

تیم امنیت رخنه‌کاو ۳۸ دقیقه مطالعه انتشار:

Insecure Deserialization یا «Deserialization ناامن» نوعی آسیب‌پذیری امنیتی است که زمانی ایجاد می‌شود که یک برنامه داده سریال‌شده غیرقابل‌اعتماد را بدون کنترل کافی دوباره به Object یا ساختار داخلی برنامه تبدیل کند. مشکل اصلی این است که فرایند Deserialization در برخی زبان‌ها صرفاً تبدیل متن به داده نیست؛ ممکن است هنگام بازسازی Object، Classها بارگذاری شوند، Methodهای خاص اجرا شوند یا وضعیت داخلی برنامه تغییر کند. در نتیجه، پردازش داده دستکاری‌شده می‌تواند به تغییر غیرمجاز اطلاعات، دور زدن منطق برنامه، افزایش سطح دسترسی، اختلال در سرویس و در برخی محیط‌ها حتی اجرای کد منجر شود.

مهم‌ترین روش جلوگیری از Insecure Deserialization این است که برنامه تا حد امکان داده سریال‌شده Native و قابل‌کنترل توسط کاربر را Deserialization نکند. برای داده‌های خارجی بهتر است از فرمت‌های ساده مانند JSON همراه با Schema و Validation دقیق استفاده شود، Integrity داده با HMAC یا امضای دیجیتال بررسی شود، فقط Typeهای کاملاً مشخص پذیرفته شوند و Runtime با اصل Least Privilege اجرا شود. Serialization و Deserialization چیست؟

Serialization و Deserialization چیست؟

برای درک Insecure Deserialization ابتدا باید تفاوت Serialization و Deserialization را بدانیم.

برنامه‌های نرم‌افزاری هنگام اجرا با انواع Object، Array، List، String، Number و ساختارهای پیچیده‌تر کار می‌کنند.

فرض کنید یک فروشگاه اینترنتی داخل حافظه برنامه Object زیر را دارد:

User
├── id: 157
├── username: aria
├── role: customer
└── credit: 250

این Object در حافظه Application وجود دارد و ممکن است شامل Propertyها، نوع داده‌ها و ارتباط با Objectهای دیگر باشد.

اگر برنامه بخواهد این وضعیت را در فایل ذخیره کند، در Cache قرار دهد، از طریق Network منتقل کند یا بعداً دوباره بازیابی کند، معمولاً باید Object را به Representation قابل ذخیره تبدیل کند.

این فرایند Serialization نام دارد.

به‌صورت مفهومی:

Object داخل برنامه
        ↓
   Serialization
        ↓
Serialized Data

Deserialization فرایند معکوس است:

Serialized Data
        ↓
  Deserialization
        ↓
Object داخل برنامه

OWASP نیز Serialization را تبدیل Object به فرمتی قابل ذخیره یا انتقال و Deserialization را بازسازی آن Object از داده ذخیره‌شده تعریف می‌کند.

در نگاه اول این فرایند کاملاً عادی به نظر می‌رسد و واقعاً هم بخش مهمی از بسیاری از Applicationهاست.

مشکل زمانی آغاز می‌شود که برنامه فرض کند:

«اگر داده Serialized به من رسیده، حتماً Object قابل‌اعتماد قبلی خودم است.»

این فرض همیشه درست نیست.

اگر Client بتواند داده را مشاهده، تغییر یا جعل کند، Trust Boundary شکسته می‌شود. Insecure Deserialization دقیقاً چیست؟

Insecure Deserialization دقیقاً چیست؟

MITRE این ضعف را با شناسه CWE-502 و عنوان Deserialization of Untrusted Data ثبت کرده است.

تعریف CWE-502 بسیار روشن است: برنامه داده غیرقابل‌اعتماد را Deserialization می‌کند بدون اینکه به اندازه کافی اطمینان حاصل کند داده و Object حاصل معتبر هستند.

در معماری امن باید چنین رابطه‌ای وجود داشته باشد:

Untrusted Data
      ↓
Validation
      ↓
Trusted Data Model
      ↓
Application Logic

اما در معماری آسیب‌پذیر ممکن است مسیر چنین باشد:

Untrusted Serialized Data
          ↓
     Deserializer
          ↓
Objectهای داخلی برنامه
          ↓
Application Logic

در این حالت Deserializer تبدیل به Trust Boundary حساسی می‌شود.

یک داده خارجی می‌تواند مستقیماً تعیین کند:

چه Objectی ساخته شود،

چه Propertyهایی داشته باشد،

چه Typeهایی Instantiate شوند،

و در بعضی Runtimeها چه Hookهایی هنگام بازسازی Object فراخوانی شوند.

به همین دلیل Deserialization یک عملیات ساده Parsing نیست.

چرا Deserialization با Parsing ساده فرق دارد؟

یکی از مهم‌ترین نکات آموزشی درباره Insecure Deserialization تفاوت آن با Parsing داده‌های ساده است.

فرض کنید برنامه JSON زیر را دریافت می‌کند:

{
  "name": "Ali",
  "age": 30
}

اگر این JSON فقط به یک Dictionary یا ساختار داده ساده تبدیل شود، برنامه معمولاً خودش تصمیم می‌گیرد چگونه از name و age استفاده کند.

اما Native Serialization Formatهای بعضی زبان‌ها می‌توانند اطلاعات بسیار بیشتری درباره Object ذخیره کنند.

برای مثال ممکن است Representation سریال‌شده مشخص کند:

Object متعلق به چه Classی بوده،

چه Fieldهایی داشته،

به چه Objectهای دیگری Reference داشته،

و چه فرایند خاصی باید هنگام بازسازی انجام شود.

OWASP اشاره می‌کند که Serialization Formatهای Native معمولاً امکانات بیشتری نسبت به JSON یا XML دارند و همین امکانات می‌توانند هنگام پردازش داده غیرقابل‌اعتماد به رفتار خطرناک تبدیل شوند.

به همین دلیل عبارت زیر اهمیت زیادی دارد:

Data Parsing ≠ Object Reconstruction

بازسازی Object می‌تواند یک عملیات بسیار قدرتمندتر باشد.

یک مثال ساده از فرایند آسیب‌پذیر

فرض کنید Application اطلاعات موقت کاربر را Serialize کرده و داخل Cookie قرار می‌دهد.

ساختار منطقی Object:

UserState
├── user_id: 1005
├── role: user
├── language: fa
└── discount: 0

سپس Server این Object را Serialize و برای مرورگر ارسال می‌کند.

در Request بعدی، مرورگر همان مقدار را برمی‌گرداند و Server آن را Deserialization می‌کند.

مشکل زمانی ایجاد می‌شود که Application فرض کند چون Object ابتدا توسط Server تولید شده است، مقدار برگشتی نیز دست‌نخورده است.

Client کنترل Cookie خود را دارد.

بنابراین اگر Integrity داده بررسی نشود، Application نباید به آن اعتماد کند.

حتی اگر Object خطر اجرای Code نداشته باشد، تغییر Propertyهایی مانند:

role
is_admin
credit
discount
account_id

ممکن است منطق Business را تحت تأثیر قرار دهد.

بنابراین Insecure Deserialization فقط به RCE مربوط نیست.

گاهی مسئله اصلی Data Integrity یا Access Control است. چرا Insecure Deserialization می‌تواند خطرناک باشد؟

چرا Insecure Deserialization می‌تواند خطرناک باشد؟

شدت این آسیب‌پذیری کاملاً وابسته به Environment است.

CWE-502 پیامدهایی مانند تغییر داده Application، ایجاد وضعیت غیرمنتظره، مصرف منابع و استفاده از Gadget Chain برای انجام عملیات غیرمجاز را مطرح می‌کند.

OWASP نیز Denial of Service، مشکلات Access Control و Remote Code Execution را در میان پیامدهای مشاهده‌شده Deserialization ناامن قرار می‌دهد.

دستکاری وضعیت Object

گاهی Serialized Data حاوی وضعیت Object است.

اگر مهاجم بتواند آن را تغییر دهد، Object بازسازی‌شده ممکن است دارای مقادیری باشد که برنامه انتظار آنها را نداشته است.

برای مثال:

Account
├── verified: true
├── role: administrator
└── balance: ...

امنیت نباید براساس Propertyهایی باشد که Client می‌تواند تعیین کند.

حتی بدون اجرای هیچ Code خارجی، تغییر Object State ممکن است برای ایجاد Vulnerability کافی باشد.

دور زدن Business Logic

فرض کنید سیستم رزرو، وضعیت یک سفارش را در Serialized Object نگه می‌دارد.

برنامه انتظار دارد مراحل فقط به ترتیب زیر تغییر کنند:

created
   ↓
paid
   ↓
confirmed
   ↓
completed

اگر User بتواند Serialized State را دستکاری کند و برنامه Object بازسازی‌شده را بدون Validation بپذیرد، ممکن است State غیرقابل‌انتظاری ایجاد شود.

این مسئله Business Logic Abuse محسوب می‌شود.

دور زدن Access Control

اگر Object شامل داده‌هایی مانند Role، Permission یا User ID باشد و Application آن داده‌ها را منبع قابل‌اعتماد Authorization بداند، Deserialization ناامن ممکن است منجر به Broken Access Control شود.

Authorization باید همیشه در سمت Server و براساس Source قابل‌اعتماد انجام شود.

Denial of Service

Deserialization فقط می‌تواند Object ایجاد نکند؛ بلکه ممکن است Object Graph بسیار بزرگ یا پیچیده‌ای را بازسازی کند.

این مسئله می‌تواند CPU، Memory یا سایر منابع را مصرف کند.

Oracle در مستندات Serialization Filtering جاوا به همین دلیل امکان محدودسازی Depth، تعداد Referenceها و اندازه Object Graph را فراهم می‌کند.

اجرای کد در شرایط خاص

خطرناک‌ترین حالت زمانی است که Deserialization Process بتواند به Classها یا Methodهایی برسد که هنگام بازسازی Object رفتار اجرایی انجام می‌دهند.

این وضعیت به زبان، کتابخانه‌ها، Classهای موجود و Configuration بستگی دارد.

بنابراین:

Insecure Deserialization

همیشه برابر با:

Remote Code Execution

نیست.

اما در بعضی Environmentها می‌تواند به آن منجر شود.

گزارش امنیتی حرفه‌ای نباید بدون Evidence هر Deserialization Issue را RCE معرفی کند. Gadget چیست؟

Gadget چیست؟

برای فهم بخشی از خطر Deserialization باید مفهوم Gadget را بدانیم.

Gadget در این زمینه به یک Class، Method یا رفتار موجود در Application یا Dependency گفته می‌شود که هنگام فرایند Object Reconstruction می‌تواند کاری فراتر از صرف بازگرداندن داده انجام دهد.

نکته مهم این است که مهاجم الزاماً Code جدیدی روی Server ارسال نمی‌کند.

ممکن است از رفتارهایی که از قبل داخل Application یا Libraryهای آن وجود دارند استفاده شود.

به شکل مفهومی:

Serialized Data
      ↓
Object A
      ↓
Existing Method
      ↓
Object B
      ↓
Existing Application Behavior

زنجیره‌ای از این رفتارها را Gadget Chain می‌نامند.

MITRE نیز Gadget Chain را مجموعه‌ای از Instanceها و Method Invocationها توصیف می‌کند که ممکن است در جریان Deserialization خودبه‌خود وارد فرایند شوند.

هدف دفاعی ما ساخت چنین زنجیره‌ای نیست.

نکته مهم برای توسعه‌دهنده این است که:

هرچه Deserializer اجازه Instantiate کردن Typeهای بیشتری داشته باشد، Attack Surface بیشتر می‌شود.

Magic Methodها و Hookهای Deserialization

بعضی زبان‌ها برای کنترل Serialization و Deserialization Hookهای خاصی دارند.

این قابلیت‌ها مفید هستند.

مثلاً Object ممکن است هنگام بازیابی لازم داشته باشد:

مقادیرش را Normalize کند،

Resource داخلی را دوباره بسازد،

یا Migration ساده‌ای انجام دهد.

اما همین Hookها باعث می‌شوند Deserialization فقط تبدیل Byteها به Property نباشد.

در PHP، مستندات رسمی unserialize() توضیح می‌دهند که هنگام بازسازی Object ممکن است Methodهای خاص مانند __unserialize() یا __wakeup() فراخوانی شوند.

بنابراین اگر User Input بتواند وارد unserialize() شود، موضوع باید بسیار جدی بررسی شود. Insecure Deserialization در PHP، Java و Python

Insecure Deserialization در PHP

PHP یکی از اکوسیستم‌هایی است که بحث Object Injection و Deserialization در آن اهمیت زیادی دارد.

توابع اصلی عبارت‌اند از:

serialize()
unserialize()

serialize() یک PHP Value را به Representation قابل ذخیره تبدیل می‌کند.

unserialize() Representation را دوباره به PHP Value تبدیل می‌کند.

مستندات رسمی PHP هشدار بسیار صریحی دارند:

داده User غیرقابل‌اعتماد نباید تحت هیچ شرایطی مستقیماً به unserialize() داده شود؛ حتی وجود گزینه allowed_classes نیز باعث نمی‌شود استفاده از داده غیرقابل‌اعتماد ذاتاً امن تلقی شود. PHP توصیه می‌کند برای داده‌ای که باید با Client ردوبدل شود از فرمت‌های استاندارد ساده‌تر مانند JSON استفاده شود.

این هشدار بسیار مهم است.

یک اشتباه رایج این است که توسعه‌دهنده تصور کند:

allowed_classes = false

یا چند Option دیگر مسئله را برای تمام حالات حل می‌کند.

در حالی که Recommendation اصلی PHP همچنان این است:

Do not unserialize untrusted data.

PHP Object Injection چیست؟

PHP Object Injection اصطلاحی است که معمولاً برای حالتی استفاده می‌شود که Object Serialization قابل‌کنترل باعث شود Objectهای غیرمنتظره در PHP بازسازی شوند.

CWE-502 نیز PHP Object Injection را از اصطلاحات مرتبط با Deserialization of Untrusted Data معرفی می‌کند.

نکته مهم آن است که وجود unserialize() به تنهایی Vulnerability نیست.

اگر داده فقط از یک Storage کاملاً قابل‌اعتماد خوانده شود و هیچ Actor غیرمجاز نتواند آن را تغییر دهد، Threat Model متفاوت است.

مسئله Source داده است.

Insecure Deserialization در Java

Java Serialization نیز یکی از نمونه‌های مهم این حوزه است.

Oracle مستقیماً هشدار می‌دهد که Deserialization داده غیرقابل‌اعتماد ذاتاً خطرناک است و باید در صورت امکان از آن اجتناب شود.

Java Serialization می‌تواند Object Graphهای پیچیده را بازسازی کند.

به همین دلیل Java دارای Serialization Filter است که می‌تواند Classهای قابل قبول را محدود کند و اندازه و Complexity گراف Object را بررسی کند.

یک طراحی دفاعی می‌تواند بگوید:

فقط Type A و Type B مجازند.
Depth حداکثر X است.
Object Count نباید از حد منطقی عبور کند.
Type ناشناخته باید Reject شود.

این کنترل‌ها Attack Surface را کاهش می‌دهند.

اما Recommendation بنیادی همچنان عدم Deserialization داده غیرقابل‌اعتماد در صورت امکان است.

Oracle در مستندات خود تأکید می‌کند که محتوی Stream تعیین می‌کند چه Objectهایی ساخته شوند و چه ارتباطی میان آنها وجود داشته باشد؛ بنابراین Input غیرقابل‌اعتماد می‌تواند رفتارهای غیرمنتظره ایجاد کند.

Insecure Deserialization در Python

در Python اصطلاح Pickling و Unpickling بسیار رایج است.

pickle می‌تواند Objectهای Python را به Byte Stream تبدیل و بعداً دوباره آنها را بازسازی کند.

مستندات رسمی Python هشدار را کاملاً صریح بیان می‌کنند: pickle امن نیست و فقط باید داده‌ای Unpickle شود که به آن اعتماد دارید. Python همچنین هشدار می‌دهد داده Pickle دستکاری‌شده می‌تواند هنگام Unpickling باعث اجرای Code شود.

بنابراین معماری زیر خطرناک است:

HTTP Request
     ↓
pickle.loads()

اگر منبع Request قابل‌اعتماد نباشد.

Python برای داده‌های خارجی، JSON را به‌عنوان گزینه‌ای مناسب‌تر مطرح می‌کند و صراحتاً تفاوت امنیتی مهمی را بیان می‌کند: Deserialization یک JSON غیرقابل‌اعتماد به‌خودی‌خود همان خطر Arbitrary Code Execution مربوط به Pickle را ایجاد نمی‌کند.

این به معنی «JSON همیشه امن است» نیست.

JSON همچنان باید:

Schema Validation،

Type Validation،

Range Validation،

Authorization،

و Business Rule Validation

داشته باشد.

اما JSON معمولاً Objectهای اجرایی Native را بازسازی نمی‌کند.

JSON و Insecure Deserialization چه تفاوتی دارند؟

گاهی هر نوع تبدیل JSON به Object «Deserialization» نامیده می‌شود.

از نظر لغوی این درست است، اما از دید امنیتی باید تفاوت قائل شد.

فرض کنید JSON زیر دریافت شود:

{
  "username": "arya",
  "role": "user"
}

خطر اصلی معمولاً این است که Application بدون Validation Propertyها را Trust کند.

مثلاً اگر Client بتواند role را به admin تغییر دهد و برنامه آن را بپذیرد، یک Integrity یا Mass Assignment Problem داریم.

اما Native Object Deserialization می‌تواند علاوه بر Fieldها، Class و رفتار Object Reconstruction را نیز تحت تأثیر قرار دهد.

بنابراین بهتر است دو مسئله جدا دیده شوند:

Untrusted Structured Data

و:

Untrusted Native Object Serialization

هر دو نیازمند Validation هستند، اما Attack Surface دومی معمولاً پیچیده‌تر است.

Cookie یکی از محل‌هایی است که Serialized Data ممکن است دیده شود.

نباید فراموش کرد:

Cookie روی Browser کاربر قرار دارد.

هر داده‌ای که سمت Client ذخیره شده است باید از دید Server بالقوه Untrusted تلقی شود، مگر اینکه Authenticity و Integrity آن با مکانیزم معتبر بررسی شود.

فرض کنید Cookie شامل این اطلاعات باشد:

user_id
role
plan
credit
expires

اگر Server فقط Cookie را Decode و Deserialization کند، Client می‌تواند Data را تغییر دهد.

راهکار مناسب معمولاً یکی از این دو مدل است:

مدل Server-Side Session

Client فقط یک Session ID تصادفی دارد:

session_id = random_identifier

و اطلاعات مهم Session سمت Server ذخیره می‌شوند.

مدل Signed State

اگر داده باید روی Client باشد، Integrity آن با MAC یا امضای معتبر محافظت می‌شود.

PHP نیز هنگام صحبت از Serialized Data خارجی استفاده از HMAC برای تشخیص دستکاری را پیشنهاد می‌کند.

اما HMAC مسئله را فقط در صورتی حل می‌کند که:

Secret امن باشد،

Verification قبل از Deserialization انجام شود،

Algorithm و Key Management صحیح باشند،

و داده واقعاً فقط توسط Source مورد اعتماد تولید شده باشد.

تفاوت Encryption و Integrity Protection

یکی از اشتباهات رایج این است که توسعه‌دهنده فکر می‌کند چون Serialized Data رمزنگاری شده، امن است.

Encryption و Integrity یک مفهوم نیستند.

Encryption می‌پرسد:

آیا فرد غیرمجاز می‌تواند محتوا را بخواند؟

Integrity می‌پرسد:

آیا فرد غیرمجاز می‌تواند محتوا را تغییر دهد بدون اینکه متوجه شویم؟

برای Deserialization، Integrity بسیار مهم است.

اگر Encryption Scheme به‌صورت Authenticated Encryption طراحی نشده باشد، صرف مخفی بودن محتوا لزوماً تغییرناپذیری آن را تضمین نمی‌کند.

بنابراین باید از مکانیزم‌های استاندارد و معتبر استفاده شود.

اختراع الگوریتم رمزنگاری اختصاصی برای Serialized Object توصیه نمی‌شود.

Insecure Deserialization در APIها و Microserviceها

در معماری Microservice ممکن است سرویس‌ها اطلاعات را از طریق Message Queue یا RPC جابه‌جا کنند.

یک تصور خطرناک این است که:

«این Message از شبکه داخلی آمده، پس Trusted است.»

Internal Network یک Trust Boundary مطلق نیست.

ممکن است یکی از Serviceها Compromise شده باشد.

ممکن است Queue Permission ضعیف باشد.

ممکن است Credential سرویس لو رفته باشد.

بنابراین پیام ورودی باید براساس قرارداد مشخص اعتبارسنجی شود.

روش امن‌تر:

Message
   ↓
Authentication
   ↓
Integrity Verification
   ↓
Schema Validation
   ↓
Business Validation
   ↓
Application Object

نه:

Message
   ↓
Native Deserialization
   ↓
Trust Everything

Insecure Deserialization در Cache و Queue

داده Serialized فقط از Browser نمی‌آید.

محل‌های دیگری نیز باید در Threat Model بررسی شوند:

Redis،

Memcached،

Message Broker،

Database،

File Cache،

Job Queue،

Session Store،

Backup،

و Shared Storage.

سؤال کلیدی این است:

چه کسی می‌تواند Data داخل این Storage را تغییر دهد؟

اگر Actor غیرمجاز یا Service دیگری امکان Write دارد، Data را نباید Blindly Trusted در نظر گرفت.

Insecure Deserialization در WordPress

WordPress برای ذخیره بعضی Arrayها و Objectها از PHP Serialization استفاده می‌کند.

مستندات رسمی WordPress نشان می‌دهند تابع maybe_serialize() می‌تواند Array یا Object را برای ذخیره‌سازی Serialize کند و maybe_unserialize() نیز داده Serialized را بازیابی می‌کند.

این رفتار به‌خودی‌خود Vulnerability نیست.

WordPress Core سال‌هاست برای ذخیره ساختارهای پیچیده در Option و Metadata از Serialization استفاده می‌کند.

مسئله امنیتی زمانی ایجاد می‌شود که Plugin یا Theme:

Serialized Data قابل‌کنترل توسط User را دریافت کند،

آن را بدون Trust Validation به unserialize() یا maybe_unserialize() بدهد،

و مهاجم نیز بتواند روی داده یا Object Type اثر بگذارد.

Pluginهای وردپرس را از کجا بررسی کنیم؟

در Code Review یک Plugin، مسیرهای زیر ارزش بررسی دارند:

$_GET
$_POST
$_COOKIE
REST API input
AJAX input
Webhook data
Imported files
Database values controlled by low-privilege users

و در سمت Sink:

unserialize()
maybe_unserialize()
custom object decoders

وجود این Functionها به تنهایی اثبات Vulnerability نیست.

باید Data Flow از Source تا Sink بررسی شود.

is_serialized امنیت داده را تأیید نمی‌کند

WordPress تابع is_serialized() را برای تشخیص اینکه یک String از نظر ساختار شبیه Serialized Data است ارائه می‌کند.

اما این تابع نمی‌گوید:

داده قابل‌اعتماد است،

Object امن است،

یا User مجاز بوده آن را تولید کند.

یعنی:

is_serialized()

یک Format Check است، نه Trust Check.

این تفاوت بسیار مهم است.

OWASP و Insecure Deserialization

Insecure Deserialization در OWASP Top 10:2017 به‌عنوان دسته مستقلی شناخته می‌شد.

در نسخه‌های جدیدتر، رویکرد OWASP بیشتر به Root Causeها تغییر کرده است.

در OWASP Top 10:2025، CWE-502 یا Deserialization of Untrusted Data زیر A08:2025 با عنوان Software or Data Integrity Failures قرار دارد.

این تغییر معنی کاهش اهمیت Deserialization را ندارد.

بلکه آن را در مسئله بزرگ‌تر Trust Boundary و Integrity Data قرار می‌دهد.

سؤال اصلی این است:

چرا Application داده‌ای را که قابل دستکاری بوده،
بدون بررسی Integrity به داده Trusted تبدیل کرده است؟

چگونه Insecure Deserialization ایجاد می‌شود؟

سناریوی رایج معمولاً چند مرحله دارد.

ابتدا Developer برای راحتی، Object داخلی را Serialize می‌کند.

سپس Serialized Data در محلی ذخیره می‌شود که Actor دیگری به آن دسترسی دارد.

مثلاً:

Cookie،

Hidden Form،

URL Parameter،

Cache مشترک،

Database Record،

یا API Message.

در مرحله بعد Application داده را دریافت کرده و فرض می‌کند همان Object اصلی و سالم است.

سپس Deserialize انجام می‌شود.

در نتیجه Trust Decision قبل از Validation اتفاق افتاده است.

به شکل خلاصه:

Trusted Object
      ↓
Serialize
      ↓
Untrusted Storage / Transport
      ↓
Attacker-controlled modification
      ↓
Deserialize
      ↓
Trusted Application Context

مشکل در مرز وسط است.

Sourceهای پرخطر برای Serialized Data

در Code Review، تمام Data Sourceها یکسان نیستند.

موارد زیر باید Untrusted در نظر گرفته شوند مگر خلاف آن ثابت شود:

  • Query String و Form Data؛ REST و GraphQL Input؛ Cookie و Local Storage برگشتی از Client؛ فایل Uploadشده؛ Message دریافت‌شده از Queue مشترک؛ داده Webhook؛ Cache قابل‌نوشتن توسط سرویس دیگر؛ Database Field قابل تغییر توسط User یا Integration؛ Session Data در Storage ناامن؛ Object دریافت‌شده از سرویس Third-Party؛ Backup یا Import File که از خارج Application وارد می‌شود.

اینکه داده قبل از Deserialization از Database آمده، به معنی Trusted بودن نیست.

Trust باید براساس منشأ واقعی و کنترل‌های Integrity تعیین شود.

چگونه Insecure Deserialization را شناسایی کنیم؟

بهترین روش ترکیب Code Review، SAST، Dependency Analysis و تست کنترل‌شده است.

مرحله اول: پیدا کردن Deserialization Sink

ابتدا تمام APIهایی را پیدا کنید که Object یا Structured State را بازسازی می‌کنند.

برای PHP:

unserialize()
maybe_unserialize()

برای Python:

pickle.load()
pickle.loads()

برای Java:

Object Serialization APIها و Frameworkهایی که Native Serialization انجام می‌دهند.

همچنین Frameworkهای Third-Party باید بررسی شوند.

مرحله دوم: پیدا کردن Source

برای هر Sink سؤال کنید:

داده از کجا آمده است؟

اگر Source User-Controlled یا External باشد، مسیر مهم است.

مرحله سوم: بررسی Integrity

قبل از Deserialization آیا Signature یا HMAC معتبر بررسی می‌شود؟

آیا Verification قبل از Deserialize انجام می‌شود یا بعد از آن؟

Validation بعد از Deserialization برای برخی Runtimeها ممکن است دیر باشد.

مرحله چهارم: بررسی Type Control

آیا Deserializer اجازه ساخت هر Class موجود در Classpath یا Application را دارد؟

یا فقط چند Type مشخص مجازند؟

مرحله پنجم: بررسی Object Graph

آیا Depth، تعداد Objectها و حجم ورودی محدود شده است؟

اگر نه، احتمال Resource Exhaustion باید بررسی شود.

تست امنیتی Deserialization چگونه باید انجام شود؟

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

برای اثبات یک مشکل لازم نیست Command اجرا شود.

در بسیاری از موارد کافی است نشان دهید:

Serialized Field قابل تغییر است،

Application تغییر را می‌پذیرد،

Object غیرمنتظره ایجاد می‌شود،

یا Type خارج از Allowlist پذیرفته می‌شود.

برای Example دفاعی می‌توان یک Object آزمایشی بی‌خطر ساخت که Property غیرحساس آن تغییر می‌کند.

اگر Application بدون Integrity Check مقدار تغییرکرده را Trust کند، Finding قابل گزارش است.

این روش از تبدیل تست امنیتی به Exploitation غیرضروری جلوگیری می‌کند.

SAST چگونه Insecure Deserialization را پیدا می‌کند؟

SAST می‌تواند مسیر Data Flow را پیدا کند:

Request Source
      ↓
Transformations
      ↓
Deserialization Sink

MITRE نیز Automated Static Analysis را برای CWE-502 روشی با اثربخشی بالا معرفی می‌کند، به‌خصوص زمانی که Tool بتواند Source و Sink را مدل کند.

با این حال SAST ممکن است False Positive داشته باشد.

مثلاً Data قبل از Sink واقعاً با Signature معتبر بررسی شده باشد.

بنابراین یافته باید دستی بررسی شود.

تفاوت Insecure Deserialization با Injection

Deserialization ناامن می‌تواند در نهایت منجر به رفتارهایی شبیه Injection شود، اما Root Cause دقیقاً یکسان نیست.

در SQL Injection:

User Data → SQL Query Syntax

در Command Injection:

User Data → OS Command Syntax

در SSTI:

User Data → Template Code

اما در Insecure Deserialization:

Serialized State → Object Reconstruction

Objectهای بازسازی‌شده سپس ممکن است باعث رفتارهای خطرناک شوند.

بنابراین Root Cause بیشتر به Trust و Object Instantiation مربوط است.

تفاوت Insecure Deserialization با Mass Assignment

Mass Assignment زمانی رخ می‌دهد که Framework Propertyهای Request را به‌طور خودکار روی Object Domain اعمال کند و User بتواند Fieldهایی را تغییر دهد که نباید کنترل کند.

مثلاً:

{
  "name": "Ali",
  "is_admin": true
}

اگر is_admin مستقیم روی User Object اعمال شود، Mass Assignment مطرح است.

در Insecure Deserialization موضوع معمولاً عمیق‌تر است و خود Representation می‌تواند Object Type و State را بازسازی کند.

البته این دو ضعف گاهی می‌توانند هم‌زمان وجود داشته باشند.

تفاوت Insecure Deserialization با Prototype Pollution

Prototype Pollution بیشتر در JavaScript و ساختار Objectها مطرح است و زمانی رخ می‌دهد که Propertyهای خاص بتوانند Prototype مشترک Objectها را تغییر دهند.

Deserialization ممکن است Vector ورود Data باشد، اما Prototype Pollution ضعف جداگانه‌ای است.

بنابراین هر JSON Parsing Problem را Insecure Deserialization نباید نامید.

دقت در Terminology باعث می‌شود Remediation درست‌تری ارائه شود. مهم‌ترین روش جلوگیری از Insecure Deserialization

مهم‌ترین روش جلوگیری از Insecure Deserialization

بهترین راهکار این است:

Untrusted Native Serialized Objects را Deserialize نکنید.

OWASP، PHP، Python و Oracle همگی به شکل‌های مختلف همین اصل را توصیه می‌کنند.

اگر Application برای Client فقط نیاز به انتقال Data دارد، از Formatهایی استفاده کنید که Data Model ساده و مشخص دارند.

مثلاً:

{
  "product_id": 152,
  "quantity": 2
}

سپس Server باید خودش Object Domain را بسازد:

JSON Input
    ↓
Schema Validation
    ↓
Validated DTO
    ↓
Application Object

نه اینکه Client مستقیماً Object Application را Serialize و کنترل کند.

JSON جایگزین مناسبی است، اما Validation را فراموش نکنید

استفاده از JSON Attack Surface Native Serialization را کاهش می‌دهد، اما JSON نباید Blindly Trusted شود.

Schema مشخص کنید.

برای مثال:

product_id:
  integer
  positive
  required

quantity:
  integer
  min: 1
  max: 100

Field اضافی Reject شود.

Type اشتباه Reject شود.

Unknown Property نادیده گرفته نشود اگر Business Logic حساس است.

و مهم‌تر:

Authorization مستقل از داده Client بررسی شود.

از DTO استفاده کنید

Data Transfer Object یا DTO کمک می‌کند بین External Data و Domain Object مرز ایجاد شود.

به‌جای اینکه Input مستقیماً User Object را ایجاد کند:

Request
   ↓
User Object

بهتر است:

Request
   ↓
CreateUserRequest DTO
   ↓
Validation
   ↓
Application Service
   ↓
User Domain Object

در این مدل DTO فقط Fieldهایی دارد که User واقعاً اجازه تعیین آنها را دارد.

Integrity Check با HMAC

اگر واقعاً نیاز دارید Serialized Data را خارج از Trust Boundary ذخیره کنید، باید امکان تشخیص تغییر آن وجود داشته باشد.

یک روش رایج HMAC است.

مدل:

Serialized Data
      +
Secret Key
      ↓
HMAC

هنگام دریافت:

Data + HMAC
      ↓
Verify HMAC
      ↓
Only if valid
      ↓
Deserialize

نکته مهم:

Verification باید قبل از Deserialization انجام شود.

PHP نیز برای Serialized Data خارجی استفاده از hash_hmac() را به‌عنوان گزینه بررسی Integrity پیشنهاد می‌کند.

Digital Signature چه زمانی مناسب است؟

در سیستم‌های چندسرویسی ممکن است HMAC مناسب نباشد، چون تمام سرویس‌های Verification نیاز به Secret مشترک پیدا می‌کنند.

امضای دیجیتال می‌تواند مدل متفاوتی ایجاد کند:

Producer با Private Key امضا می‌کند.

Consumer فقط Public Key دارد.

این روش در بعضی Architectures جداسازی Trust بهتری فراهم می‌کند.

اما طراحی Cryptographic Protocol باید استاندارد و بررسی‌شده باشد.

Allowlist برای Typeها

اگر Native Deserialization اجتناب‌ناپذیر است، Typeهای قابل بازسازی باید محدود شوند.

مثلاً Application فقط انتظار دارد:

OrderMessage
InvoiceMessage
NotificationMessage

پس Classهای دیگر باید Reject شوند.

Oracle Serialization Filter دقیقاً برای محدود کردن Classها و Object Graph در Java طراحی شده است.

Blocklist Classهای خطرناک روش ضعیف‌تری است؛ زیرا Dependency جدید ممکن است Gadget جدیدی اضافه کند.

Allowlist بهتر است:

Default Deny
+
Explicitly Allowed Types

Dependencyها و Gadget Surface

Attack Surface Deserialization فقط شامل Code نوشته‌شده توسط خود شما نیست.

هر Library داخل Application ممکن است Classهایی اضافه کند.

بنابراین اضافه کردن Dependency جدید می‌تواند بدون تغییر مستقیم Endpoint، Gadget Surface را تغییر دهد.

این دلیل دیگری است که Native Object Deserialization از Untrusted Input باید حذف شود، نه اینکه فقط «Classهای خطرناک فعلی» Block شوند.

Dependency Inventory و Software Composition Analysis نیز در این زمینه مفید هستند.

Principle of Least Privilege

فرض کنیم همه کنترل‌ها شکست خورده‌اند.

اگر Process برنامه با User محدود اجرا شود، آسیب احتمالی کمتر خواهد بود.

Application Process نباید:

به تمام File System دسترسی Write داشته باشد،

با Root اجرا شود،

Credential غیرضروری داشته باشد،

یا به تمام Network Segmentها دسترسی داشته باشد.

Least Privilege Deserialization Vulnerability را رفع نمی‌کند، اما Blast Radius را کاهش می‌دهد.

Network Egress Control

اگر Deserialization ناامن در نهایت بتواند رفتار شبکه‌ای ایجاد کند، محدود بودن Egress می‌تواند بخشی از Defense in Depth باشد.

Application Server فقط باید به Destinationهایی دسترسی داشته باشد که برای وظیفه‌اش نیاز دارد.

مثلاً Web Application معمولاً نباید بدون دلیل به هر IP و Port اینترنت دسترسی Outbound داشته باشد.

Container و Sandbox

اگر یک Component مجبور است داده پیچیده و نسبتاً غیرقابل‌اعتماد را پردازش کند، Isolation می‌تواند اثر خطا را کاهش دهد.

این Component می‌تواند:

Process جدا،

Container محدود،

User جدا،

File System محدود،

Network محدود،

CPU Limit،

Memory Limit

داشته باشد.

OWASP نیز Isolation و Sandbox را از Mitigationهای قابل استفاده در شرایطی که Deserialization اجتناب‌ناپذیر است معرفی می‌کند.

محدود کردن CPU و Memory

داده Serialized می‌تواند باعث Object Graph بزرگ یا Recursive Structure شود.

در نتیجه Resource Limit ضروری است.

برای Workerهای پردازش داده:

Timeout تعیین کنید.

Memory Limit داشته باشید.

Message Size محدود شود.

Object Graph Complexity محدود شود.

Queue Consumer Rate کنترل شود.

این موارد در جلوگیری از DoS مهم‌اند.

Error Handling امن

Deserialization Error ممکن است اطلاعات مهمی افشا کند.

برای مثال:

Class Name،

Package Name،

Library Version،

Internal Path،

Stack Trace.

این اطلاعات نباید مستقیماً در HTTP Response نمایش داده شوند.

در Production کاربر باید پیام عمومی دریافت کند.

جزئیات فنی در Log امن ثبت شوند.

Logging و Monitoring برای Deserialization

رویدادهای زیر ارزش Monitoring دارند:

Failureهای مکرر Deserialization،

Typeهای Rejectشده،

Signature Verification Failure،

Object Graph بیش از حد بزرگ،

Exceptionهای غیرعادی،

CPU Spike هنگام Decode،

Outbound Connection غیرمنتظره پس از Deserialization،

و تلاش‌های تکراری با Payload Size غیرطبیعی.

OWASP نیز Logging Exceptionهای Deserialization و Monitoring مصرف Memory، CPU، File System و Network را از کنترل‌های دفاعی معرفی می‌کند.

آیا WAF جلوی Insecure Deserialization را می‌گیرد؟

WAF ممکن است بعضی Patternها را تشخیص دهد، اما کنترل اصلی نیست.

Serialized Formatها می‌توانند:

Binary،

Encoded،

Compressed،

Encrypted

یا کاملاً Application-Specific باشند.

WAF ممکن است اصلاً Structure واقعی را نبیند.

CWE-502 نیز Firewall را یک Mitigation با اثربخشی محدود و بیشتر مناسب Defense in Depth می‌داند.

راهکار واقعی Secure Design است.

به‌روزرسانی Dependencyها چرا مهم است؟

Gadget Surface با Libraryهای Application مرتبط است.

به‌روزرسانی Dependency می‌تواند:

Vulnerability شناخته‌شده را رفع کند،

Classهای خطرناک را حذف کند،

Serialization Filtering بهتری اضافه کند،

یا Defaultهای امن‌تری داشته باشد.

اما Update جای حذف Deserialization ناامن را نمی‌گیرد.

اگر Root Cause این باشد:

Untrusted Data → Dangerous Deserializer

حتی Application کاملاً Updated هم ممکن است Vulnerable باقی بماند.

چک‌لیست دفاعی جلوگیری از Insecure Deserialization

  • داده Native Serialized را از Source غیرقابل‌اعتماد Deserialize نکنید؛ برای Client و APIها در صورت امکان از JSON یا Data Format ساده استفاده کنید؛ Input را ابتدا به DTO محدود تبدیل کرده و سپس Domain Object بسازید؛ Schema، Type، Range و Business Ruleها را اعتبارسنجی کنید؛ Authorization را از Propertyهای Client دریافت نکنید؛ اگر Serialized State خارج از Server ذخیره می‌شود Integrity آن را با HMAC یا Signature معتبر بررسی کنید؛ Verification Integrity باید قبل از Deserialization انجام شود؛ فقط Typeها و Classهای ضروری را Allowlist کنید؛ Blocklist Gadgetها را تنها دفاع اصلی قرار ندهید؛ Object Graph Depth، Size و تعداد Referenceها را محدود کنید؛ Process را با Least Privilege اجرا کنید؛ File System و Network Access را محدود کنید؛ برای Componentهای پرریسک از Isolation یا Sandbox استفاده کنید؛ CPU، Memory و Execution Time را محدود کنید؛ Errorهای Deserialization را به کاربر نمایش ندهید؛ Deserialization Exceptionها و Rejectها را Log و Monitor کنید؛ Dependencyها را به‌روز نگه دارید و SCA اجرا کنید؛ استفاده از unserialize() در PHP و pickle.load/loads() در Python را در Code Review مشخص کنید؛ در Java از Serialization Filterهای مناسب استفاده کنید؛ در WordPress مسیر داده به maybe_unserialize() یا unserialize() را بررسی کنید؛ SAST را برای Source-to-Sink Flow اجرا کنید؛ تست امنیتی را با Objectهای آزمایشی و بدون Payload مخرب انجام دهید؛ WAF را فقط به‌عنوان لایه مکمل در نظر بگیرید.

اشتباهات رایج توسعه‌دهندگان

اعتماد به Base64

Base64 یک مکانیزم امنیتی نیست.

Encoding فقط Representation داده را تغییر می‌دهد.

Serialized Data
      ↓
Base64

همچنان قابل Decode و تغییر است.

Base64:

Encryption نیست،

Signature نیست،

HMAC نیست.

اعتماد به Encryption بدون Authentication

اگر Scheme فقط Confidentiality فراهم کند ولی Integrity نداشته باشد، ممکن است کافی نباشد.

از Authenticated Encryption استاندارد استفاده کنید.

بررسی داده بعد از Deserialization

در بعضی Runtimeها خطر ممکن است هنگام خود Deserialization رخ دهد.

بنابراین اینکه ابتدا Object را Deserialize کنیم و بعد بگوییم:

if object.isSafe():

ممکن است دیر باشد.

Validation و Type Filtering باید قبل یا در خود Deserializer اعمال شوند.

Blocklist چند Class

مسدود کردن چند Class شناخته‌شده دفاع بلندمدت مناسبی نیست.

Dependencyها تغییر می‌کنند و Gadgetهای جدید ممکن است کشف شوند.

تصور اینکه داده Database امن است

اگر User قبلاً توانسته Serialized Value را داخل Database ذخیره کند، خواندن آن از DB آن را Trusted نمی‌کند.

استفاده از Object کامل برای Session

Session State باید حداقلی باشد.

به‌جای ذخیره کل User Object، اغلب این مقدار کافی است:

user_id
session_id

سپس Role و Permission از Source Server-Side معتبر خوانده شوند.

Trust کردن Service داخلی

Zero Trust فقط شعار Network نیست.

یک Service Compromise شده می‌تواند Message مخرب ارسال کند.

Inter-Service Data نیز باید Contract و Validation داشته باشد.

اگر Insecure Deserialization پیدا شد چه کنیم؟

اول Source و Sink را مشخص کنید.

باید بدانید:

داده از کجا می‌آید؟

چه کسی می‌تواند آن را تغییر دهد؟

Deserializer چیست؟

چه Typeهایی قابل ساخت هستند؟

آیا Integrity Verification وجود دارد؟

Process چه Permissionهایی دارد؟

و Object حاصل در کجای Business Logic استفاده می‌شود؟

سپس بهترین اصلاح معمولاً حذف Native Deserialization از Trust Boundary است.

مثلاً:

Serialized User Object

به:

Signed Session ID

یا:

Validated JSON DTO

تبدیل شود.

اگر حذف فوری ممکن نیست:

Integrity Check،

Type Allowlist،

Resource Limits،

Isolation،

و Least Privilege

باید به‌عنوان Mitigation موقت اجرا شوند.

Incident Response پس از Insecure Deserialization

اگر Vulnerability در Production وجود داشته است، باید بررسی شود آیا فقط Bug وجود داشته یا Exploitation نیز رخ داده است.

مواردی که باید بررسی شوند:

Deserialization Error Logها،

Process Creationهای غیرعادی،

File Changeها،

Network Connectionهای غیرمنتظره،

Privilege Changeها،

User Stateهای غیرمعمول،

Sessionهای مشکوک،

و تغییر داده Application.

اگر Serialized Data حاوی Authentication یا Authorization State بوده، تمام Sessionها و Tokenهای مرتبط باید در Scope Incident بررسی شوند.

اگر Secret احتمالی در معرض خطر قرار گرفته است، Rotation لازم است.

Threat Modeling برای Deserialization

در مرحله طراحی، این سؤال‌ها باید پرسیده شوند:

آیا واقعاً باید Object کامل Serialize شود؟

آیا Client نیاز دارد State را نگه دارد؟

آیا یک Identifier ساده کافی نیست؟

چه Actorهایی می‌توانند Serialized Data را تغییر دهند؟

چه اتفاقی می‌افتد اگر Object ساختگی باشد؟

چه Typeهایی باید مجاز باشند؟

اگر Integrity Check Fail شد چه اتفاقی می‌افتد؟

اگر Deserializer Memory زیادی مصرف کرد چه؟

این سؤال‌ها اغلب قبل از نوشتن Code مشکل را آشکار می‌کنند.

یک معماری امن برای Session

مدل پرخطر:

Browser
   ↓
Serialized User Object
   ↓
Server Deserialize
   ↓
Trust Role / Permissions

مدل مناسب‌تر:

Browser
   ↓
Random Session Identifier
   ↓
Server-side Session Store
   ↓
User ID
   ↓
Authorization Database

در این حالت Client نمی‌تواند Role یا Permission را با دستکاری Serialized Object تغییر دهد.

معماری امن برای Microservice Message

به‌جای ارسال Native Object:

Java Serialized UserObject

می‌توان یک Message Contract مشخص داشت:

{
  "event_type": "ORDER_CREATED",
  "order_id": 1502,
  "user_id": 72,
  "version": 1
}

سپس Consumer:

Schema را Validation می‌کند،

Producer را Authenticate می‌کند،

Integrity Message را بررسی می‌کند،

و Domain Object خودش را می‌سازد.

این معماری Coupling را نیز کاهش می‌دهد.

معماری امن برای Import

Import File نباید شامل Object Native برنامه باشد مگر ضرورت جدی وجود داشته باشد.

فرمت‌هایی مانند:

JSON،

CSV،

یا XML با Parser و Schema امن

معمولاً امکان Validation شفاف‌تری ایجاد می‌کنند.

Import Process باید داده را به‌عنوان Data ببیند، نه Instruction برای ساخت Arbitrary Object.

Insecure Deserialization در ML و AI

این موضوع فقط به وب‌سایت‌های سنتی محدود نیست.

Model Fileها نیز ممکن است از Serialization Formatهایی استفاده کنند که Object یا Code Behavior را بازسازی می‌کنند.

CWE-502 حتی نمونه‌های جدیدی از آسیب‌پذیری‌های مرتبط با Platformهای AI/ML و Pickled Model Objectها را در فهرست Observed Examples خود دارد.

بنابراین فایل Model دانلودشده از منبع غیرقابل‌اعتماد نباید کورکورانه Load شود.

در Pipelineهای AI نیز Source Artifact، Signature و Serialization Format اهمیت دارند.

چرا این آسیب‌پذیری همچنان مهم است؟

یکی از دلایل ماندگاری Insecure Deserialization راحتی Native Serialization است.

برای Developer بسیار ساده است:

Object → Serialize → Store

و بعد:

Load → Deserialize → Object

اما همین راحتی باعث می‌شود Trust Boundary پنهان شود.

هرگاه Serialized Data از Process امن خارج شود، باید پرسید:

چه کسی در مسیر می‌تواند آن را تغییر دهد؟

Browser؟

Database User؟

Queue Producer؟

Service دیگر؟

Backup Operator؟

Third Party؟

اگر جواب «شخصی خارج از Trust Boundary» باشد، Deserialization باید دوباره طراحی شود.

چگونه گزارش Insecure Deserialization حرفه‌ای بنویسیم؟

گزارش نباید فقط بگوید:

«سایت unserialize دارد.»

باید مشخص کند:

Source داده چیست،

Sink کجاست،

چه Actorی داده را کنترل می‌کند،

چه Integrity Controlی وجود ندارد،

چه Behaviorای اثبات شده،

و Impact واقعی چیست.

اگر فقط State Manipulation اثبات شده است، گزارش نباید RCE قطعی اعلام کند.

می‌توان نوشت:

داده قابل‌کنترل توسط کاربر بدون Integrity Verification
Deserialization می‌شود و Object State غیرمجاز قابل ایجاد است.

اگر Type غیرمنتظره قابل Instantiate است، همان مورد ثبت شود.

گزارش دقیق از گزارش اغراق‌آمیز ارزش بیشتری دارد.

اولویت‌بندی شدت Insecure Deserialization

Severity به Context وابسته است.

موارد مهم:

Endpoint عمومی است یا Authenticated؟

داده Signature دارد؟

User چه مقدار کنترل دارد؟

Native Object Type کنترل می‌شود؟

Classهای موجود چه قابلیت‌هایی دارند؟

Application با چه Permissionی اجرا می‌شود؟

آیا فقط Data State تغییر می‌کند؟

آیا Authorization تحت تأثیر قرار می‌گیرد؟

آیا Object Graph می‌تواند DoS ایجاد کند؟

آیا رفتار اجرایی قابل اثبات است؟

بنابراین دو Finding با عنوان یکسان می‌توانند Severity کاملاً متفاوت داشته باشند.

آیا HMAC به‌تنهایی کافی است؟

HMAC در سناریویی که فقط باید مطمئن شویم داده توسط Server تولید و تغییر نکرده مفید است.

اما چند محدودیت دارد.

اگر Secret لو برود، Integrity از بین می‌رود.

اگر برنامه قبل از Verification Deserialization کند، HMAC کمکی نمی‌کند.

اگر منبع Server-Side خودش Compromise شده باشد، HMAC مشکل را حل نمی‌کند.

اگر Object دارای Logic خطرناک باشد و Application خودش Object غیرمناسب تولید کند، HMAC هم مانع نمی‌شود.

بنابراین HMAC یکی از کنترل‌هاست، نه جایگزین Secure Design.

آیا Serialization همیشه بد است؟

خیر.

Serialization یک قابلیت ضروری و مفید است.

مشکل Serialization نیست.

مشکل Trust Boundary است.

Serialize کردن Object برای Cache داخلی Process می‌تواند کاملاً منطقی باشد.

Serialize کردن داده برای Storage کنترل‌شده نیز ممکن است مناسب باشد.

اما زمانی که داده از محیطی عبور می‌کند که Actor غیرقابل‌اعتماد قادر به Modify آن است، باید مدل امنیتی تغییر کند.

آیا Deserialize کردن داده Trusted همیشه بی‌خطر است؟

خیر، حتی داده Trusted می‌تواند Corrupt یا بسیار بزرگ باشد.

بنابراین:

Size Limit،

Error Handling،

Version Handling،

Object Graph Limit،

و Resource Control

همچنان مهم هستند.

Security فقط درباره Attacker نیست؛ Robustness نیز اهمیت دارد.

نقش Fail Closed

اگر Integrity Check شکست خورد، Application نباید بگوید:

«احتمالاً مشکلی نیست، Object را ادامه می‌دهیم.»

رفتار مناسب Reject کردن داده است.

مثلاً:

Invalid Signature
       ↓
Reject
       ↓
Log Security Event

نه:

Invalid Signature
       ↓
Deserialize Anyway

Fail Closed در این مرز امنیتی اهمیت زیادی دارد.

سؤالات متداول درباره Insecure Deserialization

Insecure Deserialization چیست؟

Insecure Deserialization زمانی رخ می‌دهد که Application داده سریال‌شده غیرقابل‌اعتماد را بدون Validation، Integrity Check یا Type Control کافی به Object داخلی تبدیل کند. این ضعف با CWE-502 شناخته می‌شود.

Serialization چیست؟

Serialization فرایند تبدیل Object یا State داخلی برنامه به Representation قابل ذخیره یا انتقال است.

Deserialization چیست؟

Deserialization فرایند بازسازی Object یا ساختار داخلی برنامه از Serialized Data است.

CWE مربوط به Insecure Deserialization چیست؟

شناسه اصلی آن CWE-502 یعنی Deserialization of Untrusted Data است.

Insecure Deserialization در OWASP Top 10 کجاست؟

در OWASP Top 10:2025، CWE-502 در دسته A08:2025 Software or Data Integrity Failures قرار دارد.

آیا Insecure Deserialization همیشه باعث RCE می‌شود؟

خیر. Impact می‌تواند از تغییر Object State و دور زدن Business Logic تا DoS یا در بعضی Environmentها RCE متفاوت باشد.

Gadget Chain چیست؟

Gadget Chain مجموعه‌ای از Classها یا Methodهای از قبل موجود است که رفتار آنها در جریان Deserialization ممکن است به‌صورت زنجیره‌ای به عملیات غیرمجاز منجر شود.

آیا JSON هم Insecure Deserialization دارد؟

JSON همچنان نیازمند Validation است، اما تبدیل JSON ساده به Primitive Data Structures معمولاً همان Attack Surface Native Object Serialization مانند PHP Object Serialization، Java Serialization یا Python Pickle را ندارد.

آیا pickle در Python امن است؟

برای داده غیرقابل‌اعتماد خیر. مستندات رسمی Python صراحتاً می‌گویند فقط داده‌ای را Unpickle کنید که به آن اعتماد دارید.

آیا unserialize در PHP امن است؟

PHP هشدار می‌دهد داده غیرقابل‌اعتماد نباید مستقیماً وارد unserialize() شود، حتی با Optionهایی مانند allowed_classes.

آیا Serialization در WordPress وجود دارد؟

بله. WordPress برای بعضی Arrayها و Objectها از Serialization استفاده می‌کند و توابعی مانند maybe_serialize() و maybe_unserialize() دارد. وجود این توابع به‌تنهایی Vulnerability نیست؛ منشأ داده و Trust Boundary تعیین‌کننده است.

آیا is_serialized وردپرس داده را امن می‌کند؟

خیر. is_serialized() فقط بررسی می‌کند String از نظر ساختار Serialized به نظر می‌رسد؛ Authenticity یا Authorization داده را تأیید نمی‌کند.

بهترین روش جلوگیری از Insecure Deserialization چیست؟

تا حد امکان Native Serialized Object را از Untrusted Source قبول نکنید. از Data Format ساده، Schema Validation، DTO، Integrity Check، Type Allowlist و Least Privilege استفاده کنید.

HMAC چه کمکی می‌کند؟

HMAC امکان تشخیص تغییر Serialized Data را فراهم می‌کند، مشروط بر اینکه قبل از Deserialization Verification شود و Secret Key امن باقی بماند.

آیا WAF از Insecure Deserialization جلوگیری می‌کند؟

به‌تنهایی خیر. WAF فقط یک کنترل مکمل است و ممکن است Serialized Data پیچیده یا Binary را به‌درستی تحلیل نکند.

آیا Base64 باعث امن شدن Serialized Data می‌شود؟

خیر. Base64 فقط Encoding است و هیچ Confidentiality یا Integrity امنیتی ایجاد نمی‌کند.

آیا Encryption به‌تنهایی کافی است؟

نه لزوماً. Integrity و Authenticity نیز باید تضمین شوند. در عمل باید از طراحی‌های استاندارد مانند Authenticated Encryption استفاده کرد.

جمع‌بندی

Insecure Deserialization یکی از آسیب‌پذیری‌هایی است که در ظاهر از یک قابلیت کاملاً عادی برنامه‌نویسی آغاز می‌شود: ذخیره و بازیابی Objectها.

Serialization برای تبدیل Object به داده قابل انتقال یا ذخیره استفاده می‌شود و Deserialization آن داده را دوباره به Object تبدیل می‌کند.

مشکل زمانی ایجاد می‌شود که Serialized Data از یک Trust Boundary عبور کند و Application همچنان آن را همان Object قابل‌اعتماد اولیه فرض کند.

داده‌ای که داخل Cookie، API Request، Queue، Cache مشترک، Import File یا Database قابل‌ویرایش قرار گرفته است باید بالقوه Untrusted در نظر گرفته شود.

اگر این داده مستقیماً وارد Native Deserializer شود، ممکن است Object State تغییر کند، Business Logic دور زده شود، Authorization تحت تأثیر قرار بگیرد، منابع سیستم مصرف شوند و در بعضی Runtimeها Classها و Methodهای موجود به رفتارهای جدی‌تر منجر شوند.

به همین دلیل CWE-502 همچنان یکی از ضعف‌های مهم امنیت نرم‌افزار است و در OWASP Top 10:2025 زیر A08 Software or Data Integrity Failures قرار دارد.

بهترین دفاع حذف Trust Boundary خطرناک است.

اگر Client فقط باید Data ارسال کند، به‌جای Native Serialized Object از JSON یا Format ساده با Schema دقیق استفاده کنید.

ورودی را ابتدا به DTO محدود تبدیل کنید.

Propertyهای حساس مانند Role و Permission را از Client دریافت نکنید.

اگر Serialized Data واقعاً باید خارج از Server نگهداری شود، Integrity آن را قبل از Deserialization با HMAC یا Signature معتبر بررسی کنید.

در Java از Serialization Filtering و محدودیت Object Graph استفاده کنید.

در Python داده غیرقابل‌اعتماد را با Pickle بازسازی نکنید.

در PHP ورودی User را به unserialize() ندهید.

در WordPress نیز وجود Serialization در Core طبیعی است، اما Plugin و Theme نباید داده غیرقابل‌اعتماد را کورکورانه وارد maybe_unserialize() یا unserialize() کنند.

Least Privilege، Isolation، Resource Limits، Egress Filtering، Dependency Management، Logging، Monitoring و SAST نیز لایه‌های مهم Defense in Depth هستند.

در نهایت هنگام بررسی هر سیستم Serialization یک سؤال کلیدی مطرح کنید:

«آیا کسی خارج از Trust Boundary می‌تواند این Serialized Data را قبل از Deserialization مشاهده، جایگزین یا تغییر دهد؟»

اگر پاسخ مثبت است، داده نباید بدون کنترل‌های امنیتی قوی به Object قابل‌اعتماد برنامه تبدیل شود.

مطالب مرتبط