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

DOM Clobbering چیست؟ بررسی یکی از آسیب‌پذیری‌های کمتر شناخته‌شده JavaScript

DOM Clobbering یک آسیب‌پذیری Client-Side است که از رفتار Named Properties مرورگر و عناصر دارای id یا name برای تحت تأثیر قرار دادن متغیرها و Propertyهای JavaScript استفاده می‌کند. این ضعف در صورت ترکیب با HTML کنترل‌شده و کد ناامن می‌تواند به تغییر رفتار برنامه، Open Redirect و حتی زنجیره‌های منتهی به XSS منجر شود. استفاده از HTML Sanitization، ES Modules، Type Checking، CSP و حذف وابستگی به Global Variableهای window و document از مهم‌ترین راهکارهای جلوگیری از DOM Clobbering هستند.

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

پاسخ کوتاه: DOM Clobbering یک تکنیک سوءاستفاده از رفتار Named Properties در مرورگر است که طی آن عناصر HTML دارای id یا name می‌توانند با متغیرها، Propertyها یا APIهایی که JavaScript انتظار دارد تداخل ایجاد کنند. اگر مهاجم بتواند HTML کنترل‌شده وارد صفحه کند و کد سایت به متغیرهای Global یا Propertyهای window و document اعتماد کند، ممکن است رفتار JavaScript تغییر کند و در شرایط خاص به XSS، Open Redirect، بارگذاری Resource ناخواسته یا اختلال در منطق برنامه منجر شود.

DOM یا Document Object Model یکی از اصلی‌ترین بخش‌های معماری وب است. مرورگر بعد از دریافت HTML، ساختاری درختی از عناصر صفحه ایجاد می‌کند و JavaScript از طریق DOM می‌تواند محتوای صفحه، Attributeها، فرم‌ها، لینک‌ها، تصاویر و بسیاری از اجزای رابط کاربری را مشاهده یا تغییر دهد.

همین تعامل عمیق بین HTML و JavaScript قابلیت‌هایی مانند رابط‌های تعاملی، فرم‌های پویا، Single Page Applicationها، پنل‌های مدیریتی و صدها قابلیت دیگر را ممکن کرده است.

اما در کنار این مزایا، رفتارهای قدیمی و سازگار با نسخه‌های اولیه وب نیز در مرورگرهای مدرن باقی مانده‌اند.

یکی از این رفتارها Named Property Access است.

در برخی شرایط، وقتی یک عنصر HTML دارای id یا name باشد، مرورگر می‌تواند آن عنصر را به شکلی در دسترس JavaScript قرار دهد که شبیه یک Property روی window، document یا بعضی Objectهای دیگر به نظر برسد.

استاندارد HTML صراحتاً Named Properties را برای Window و Document تعریف می‌کند. برای نمونه، ID بعضی عناصر داخل Document می‌تواند بخشی از مجموعه Propertyهای Named روی window شود. همین رفتار تاریخی یکی از پایه‌های DOM Clobbering است.

مشکل از جایی آغاز می‌شود که Developer تصور می‌کند یک نام همیشه به متغیر یا Object مورد انتظار او اشاره می‌کند، در حالی که HTML کنترل‌شده توسط کاربر می‌تواند باعث شود مرورگر مقدار دیگری را با همان نام در اختیار JavaScript قرار دهد.

به این فرایند اصطلاحاً Clobbering یا «جایگزین کردن و تحت تأثیر قرار دادن یک نام موجود» گفته می‌شود.

DOM Clobbering در مقایسه با XSS، SQL Injection یا CSRF کمتر شناخته شده است، اما در Applicationهای بزرگ، سیستم‌هایی که User-Generated HTML دارند، Rich Text Editorها، سیستم‌های Comment، CMSها و برنامه‌هایی که از متغیرهای Global استفاده می‌کنند، می‌تواند اهمیت زیادی پیدا کند.

OWASP این تکنیک را نوعی HTML-only Injection و Code-Reuse Attack توصیف می‌کند که در آن عنصرهایی با id یا name خاص می‌توانند با متغیرها یا APIهای حساس برنامه تداخل ایجاد کنند.

در این مقاله از رخنه‌کاو بررسی می‌کنیم DOM Clobbering چیست، چرا مرورگر اجازه چنین رفتاری را می‌دهد، چه تفاوتی با DOM XSS دارد، چه شرایطی برای ایجاد Vulnerability لازم است، چه بخش‌هایی از JavaScript بیشتر در معرض خطر هستند و چگونه با HTML Sanitization، CSP، Type Checking، Scope مناسب و Secure Coding از DOM Clobbering جلوگیری کنیم.

DOM چیست و چه ارتباطی با JavaScript دارد؟

DOM یک Interface برنامه‌نویسی برای Documentهای HTML و XML است.

وقتی مرورگر صفحه زیر را دریافت می‌کند:

<div id="profile">
    <span>کاربر</span>
</div>

این HTML فقط یک رشته Text باقی نمی‌ماند.

مرورگر آن را Parse می‌کند و Nodeهایی ایجاد می‌کند که JavaScript می‌تواند با آن‌ها تعامل داشته باشد.

برای مثال:

const profile = document.getElementById("profile");

در این حالت Developer صریحاً از مرورگر می‌خواهد Element دارای ID مشخص را پیدا کند.

این الگو روشن و قابل پیش‌بینی است.

اما مرورگرهای وب برای حفظ سازگاری با وب قدیمی، قابلیت‌هایی دارند که دسترسی به بعضی عناصر Named را بدون استفاده از متدهایی مانند getElementById() نیز ممکن می‌کنند.

همین قابلیت پایه اصلی DOM Clobbering است.

Named Property Access چیست؟

Named Property Access رفتاری است که در آن برخی عناصر HTML براساس id یا name می‌توانند به شکل Property روی Objectهایی مانند window و document ظاهر شوند.

به‌صورت مفهومی اگر صفحه دارای عنصری با ID مشخص باشد، ممکن است Browser Reference مربوط به آن Element را از طریق فضای نام Global نیز در دسترس قرار دهد.

این رفتار بخشی از استاندارد HTML است و صرفاً یک Bug در یک Browser خاص محسوب نمی‌شود. مجموعه نام‌هایی که می‌توانند روی Window ظاهر شوند شامل ID برخی عناصر Document و مقدار name برای گروهی از عناصر است.

هدف اولیه این رفتار تسهیل کار با صفحات HTML در سال‌های ابتدایی وب و حفظ Backward Compatibility بوده است.

اما در Application مدرن، استفاده ناآگاهانه از آن می‌تواند خطرناک باشد.

Developer ممکن است تصور کند:

window.config

همیشه Object تنظیماتی است که خودش ایجاد کرده است.

اما اگر نام config تحت شرایط خاص توسط DOM تحت تأثیر قرار گیرد، Application ممکن است Object دیگری دریافت کند.

این برخورد میان Namespace کد JavaScript و Named Elementهای DOM همان چیزی است که DOM Clobbering را امکان‌پذیر می‌کند. DOM Clobbering دقیقاً چیست؟

DOM Clobbering دقیقاً چیست؟

DOM Clobbering زمانی رخ می‌دهد که یک عنصر HTML با استفاده از Attributeهایی مانند id یا name باعث شود JavaScript به Object یا Property متفاوتی از آنچه Developer انتظار دارد دسترسی پیدا کند.

در چنین وضعیتی مهاجم الزاماً JavaScript تزریق نمی‌کند.

ممکن است تنها بتواند HTML محدودی وارد صفحه کند.

برای مثال:

  • Comment با HTML محدود
  • محتوای Rich Text
  • HTML Sanitized
  • توضیحات Profile
  • محتوای CMS
  • Widget سفارشی
  • محتوای Importشده از سیستم دیگر

ممکن است <script> و Event Handlerها کاملاً حذف شوند.

با این حال اگر id و name همچنان مجاز باشند، مهاجم ممکن است بتواند Namespace مربوط به JavaScript را تحت تأثیر قرار دهد.

PortSwigger نیز DOM Clobbering را تکنیکی معرفی می‌کند که در آن HTML تزریق‌شده می‌تواند DOM را دستکاری کرده و رفتار JavaScript برنامه را تغییر دهد؛ این تکنیک به‌خصوص در شرایطی اهمیت پیدا می‌کند که XSS مستقیم ممکن نیست اما برخی Markupهای HTML هنوز پذیرفته می‌شوند.

چرا نام DOM Clobbering انتخاب شده است؟

واژه Clobber در حوزه برنامه‌نویسی معمولاً به معنی Overwrite یا تحت تأثیر قرار دادن یک مقدار موجود استفاده می‌شود.

در DOM Clobbering، مهاجم ممکن است متغیر JavaScript را به معنای سنتی Overwrite نکند.

در عوض Browser Resolution Mechanism باعث می‌شود یک نام به DOM Element دیگری Resolve شود.

از دید Developer نتیجه شبیه این است که متغیر یا Property مورد انتظار «له شده» و چیز دیگری جای آن آمده است.

برای نمونه Application تصور می‌کند:

settings.url

یک String معتبر است.

اما اگر settings یا Property داخلی آن از طریق Named DOM Access تحت تأثیر قرار گیرد، نتیجه می‌تواند یک Element یا HTMLCollection باشد.

اگر برنامه بدون Type Checking مقدار را وارد یک Sink حساس کند، Vulnerability شکل می‌گیرد.

یک نمونه ساده و دفاعی از مشکل

فرض کنید Developer چنین منطقی نوشته است:

const target = window.redirectTarget || "/dashboard";

هدف Developer این است که اگر تنظیم Global خاصی وجود نداشت، User به Dashboard هدایت شود.

مشکل این الگو این است که window.redirectTarget مستقیماً از Global Window Namespace خوانده می‌شود.

اگر در بخشی از صفحه HTML قابل‌کنترل وجود داشته باشد و نام مشابهی بتواند از طریق DOM ایجاد شود، نوع و مقدار window.redirectTarget دیگر الزاماً همان چیزی نیست که Developer انتظار داشته است.

نسخه امن‌تر می‌تواند تنظیمات را داخل Scope کنترل‌شده نگه دارد:

const appConfig = Object.freeze({
    redirectTarget: "/dashboard"
});

const target = appConfig.redirectTarget;

در این حالت برنامه برای Configuration به Named Properties موجود روی window وابسته نیست.

اصل امنیتی مهم این است:

DOM را به‌عنوان محل ذخیره متغیرهای امنیتی برنامه در نظر نگیرید. چه شرایطی برای DOM Clobbering لازم است؟

چه شرایطی برای DOM Clobbering لازم است؟

وجود Named Properties به تنهایی Vulnerability نیست.

برای ایجاد یک DOM Clobbering قابل‌استفاده معمولاً چند شرط باید کنار هم قرار بگیرند.

امکان وارد کردن HTML

مهاجم باید بتواند HTML یا بخشی از DOM را تحت تأثیر قرار دهد.

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

Stored Input معمولاً خطر بیشتری دارد؛ زیرا Markup می‌تواند برای کاربران مختلف نمایش داده شود.

مجاز بودن Attributeهای حساس

Sanitizer ممکن است <script> را حذف کند اما Attributeهایی مانند:

id
name

را نگه دارد.

همین Attributeها برای بسیاری از الگوهای DOM Clobbering اهمیت دارند.

وجود JavaScript وابسته به Named Properties

Application باید JavaScriptای داشته باشد که به نام قابل‌Clobber شدن اعتماد کند.

برای مثال استفاده از:

window.someValue
document.someValue

بدون Validation می‌تواند خطرناک باشد.

وجود Sink حساس

تغییر مقدار فقط زمانی پیامد امنیتی جدی ایجاد می‌کند که Value نهایی وارد عملیات حساسی شود.

مانند:

Dynamic URL

Redirect

Script Source

HTML Rendering

Navigation

Network Request

Configuration

یا تصمیمات Security-Sensitive.

این مدل شبیه مفهوم Source و Sink در سایر DOM-Based Vulnerabilityهاست.

Source و Sink در DOM Clobbering

در تحلیل امنیت Client-Side معمولاً دو مفهوم مهم وجود دارند:

Source مکانی است که داده کنترل‌شده توسط مهاجم وارد برنامه می‌شود.

Sink عملیاتی است که استفاده ناامن از داده در آن می‌تواند اثر امنیتی ایجاد کند.

در DOM Clobbering، Source می‌تواند یک Element دارای id یا name کنترل‌شده باشد.

Sink ممکن است:

location.assign(...)

یا:

script.src = ...

یا:

element.innerHTML = ...

باشد.

PortSwigger نیز در توضیح DOM-Based Vulnerabilities تأکید می‌کند که مشکل زمانی ایجاد می‌شود که یک مقدار قابل‌کنترل از Source به Sink خطرناک منتقل شود.

بنابراین وجود یک Element Named به تنهایی آسیب‌پذیری قابل‌استفاده نیست.

جریان داده میان آن Element و یک عملیات حساس اهمیت دارد. DOM Clobbering چه تفاوتی با XSS دارد؟

DOM Clobbering چه تفاوتی با XSS دارد؟

این دو مفهوم به یکدیگر مرتبط‌اند اما یکسان نیستند.

Cross-Site Scripting یا XSS معمولاً زمانی ایجاد می‌شود که داده کنترل‌شده توسط مهاجم به شکلی وارد صفحه شود که Browser آن را به‌عنوان JavaScript اجرا کند.

در DOM Clobbering، مهاجم ممکن است هیچ JavaScriptای مستقیماً وارد صفحه نکند.

در عوض HTML روی Object Resolution تأثیر می‌گذارد.

می‌توان تفاوت را چنین خلاصه کرد:

ویژگیDOM ClobberingXSS
ورودی اصلیHTML و Named ElementScript یا داده وارد Sink اجرایی
نیاز مستقیم به <script>معمولاً خیرخیر در همه انواع، ولی اجرای JavaScript هدف اصلی است
هدف اولیهتغییر Reference یا رفتار JavaScriptاجرای JavaScript در Context سایت
وابستگی به id و nameبسیار رایجالزامی نیست
Named Propertiesمحور اصلیمعمولاً محور اصلی نیست
امکان تبدیل به XSSدر برخی شرایطخود Vulnerability اجرای Script است

مهم‌ترین نکته این است که DOM Clobbering ممکن است خودش بخشی از زنجیره‌ای باشد که در نهایت به XSS منجر می‌شود.

OWASP نیز اشاره می‌کند که DOM Clobbering در بعضی سناریوها می‌تواند Markup ظاهراً امن را به مسیری برای اجرای JavaScript تبدیل کند.

DOM Clobbering و HTML Injection چه تفاوتی دارند؟

HTML Injection مفهوم گسترده‌تری است.

در HTML Injection، مهاجم قادر است Markup را وارد صفحه کند.

نتیجه ممکن است تنها تغییر ظاهر سایت باشد.

مثلاً:

متن جدید

تصویر

لینک

یا Layout متفاوت.

اما DOM Clobbering زمانی رخ می‌دهد که HTML تزریق‌شده با JavaScript Environment تعامل کند و یک Name Collision ایجاد شود.

بنابراین:

HTML Injection
        ↓
در صورت وجود شرایط خاص
        ↓
DOM Clobbering
        ↓
در صورت وجود Sink حساس
        ↓
Impact امنیتی

هر HTML Injection الزاماً DOM Clobbering نیست.

اما HTML Injection می‌تواند پیش‌نیاز آن باشد.

DOM Clobbering و Prototype Pollution

Prototype Pollution نیز می‌تواند Property Resolution در JavaScript را تحت تأثیر قرار دهد، اما مکانیزم آن کاملاً متفاوت است.

در Prototype Pollution مهاجم تلاش می‌کند Object Prototype Chain را تغییر دهد.

در DOM Clobbering رفتار Named DOM Properties مورد سوءاستفاده قرار می‌گیرد.

در Prototype Pollution ممکن است Property به:

Object.prototype

اضافه شود.

اما در DOM Clobbering Elementهای واقعی HTML در DOM باعث Namespace Collision می‌شوند.

شباهت اصلی هر دو Vulnerability این است که Developer مقداری را از یک Object دریافت می‌کند و تصور می‌کند منبع و Type آن قابل اعتماد است.

در هر دو مورد Defensive Programming و Type Checking اهمیت زیادی دارد. Clobbering در window و document

Clobbering در window

window Global Object اصلی در JavaScript مرورگر است.

Variableهای Global سنتی و بسیاری از Browser APIها از طریق آن قابل دسترسی هستند.

برای همین استفاده گسترده از window برای ذخیره Configuration سفارشی می‌تواند سطح حمله را افزایش دهد.

مثلاً:

window.appConfig = ...
window.redirect = ...
window.apiBase = ...

اگر بخش‌هایی از برنامه براساس Named Access عمل کنند، امکان برخورد نام افزایش پیدا می‌کند.

OWASP توصیه می‌کند از window و document به‌عنوان محل عمومی برای ذخیره متغیرهای حساس استفاده نشود.

الگوی بهتر استفاده از Module Scope است.

مثلاً:

const applicationConfig = {
    apiBase: "/api",
    redirectPath: "/account"
};

یا در JavaScript Module:

export const applicationConfig = Object.freeze({
    apiBase: "/api"
});

این Value دیگر به Named Propertyهای DOM وابسته نیست.

Clobbering در document

document نیز Named Property Access دارد.

استاندارد HTML مجموعه‌ای از Named Elementها را برای Document تعریف می‌کند که می‌توانند با id یا name در Resolution Propertyها نقش داشته باشند.

بنابراین Patternهایی مانند:

document.config
document.settings
document.userData

برای Application Data الگوی مناسبی نیستند.

استفاده از APIهای صریح مانند:

document.getElementById(...)
document.querySelector(...)

قابل پیش‌بینی‌تر است.

البته حتی در این حالت نیز Element انتخاب‌شده باید Validation شود و نباید Value آن به‌صورت خودکار Trusted فرض شود.

Clobbering در فرم‌های HTML

یکی از نمونه‌های بسیار جالب DOM Clobbering مربوط به Formها است.

Form Elementها دارای Propertyها و Methodهای Built-in هستند.

اما کنترل‌های داخل Form که name خاصی دارند می‌توانند در برخی شرایط با این Propertyها برخورد کنند.

استاندارد HTML حتی به‌صورت مستقیم هشدار می‌دهد که DOM Clobbering یکی از علل رایج مشکلات امنیتی است و نباید برای کنترل‌های Form از نام Propertyهای Built-in استفاده کرد.

برای مثال Form ممکن است Propertyای برای Method خود داشته باشد.

اگر Input داخلی نامی برابر با یک Property حساس داشته باشد، JavaScript ممکن است به جای مقدار Built-in به Element داخلی اشاره کند.

این مسئله فقط امنیتی نیست.

گاهی باعث Bugهای عجیب و دشوار در Frontend می‌شود.

نام‌های حساس در فرم‌ها

Developer باید هنگام انتخاب name و id برای Form Controlها دقت کند.

نام‌هایی که با APIهای Built-in Form برخورد می‌کنند می‌توانند مشکل ایجاد کنند.

الگوی بهتر استفاده از Prefixهای اختصاصی است.

مثلاً:

profile_email
profile_display_name
checkout_phone

به جای نام‌های عمومی و مبهم.

چگونه DOM Clobbering می‌تواند روی Redirect اثر بگذارد؟

فرض کنید Application مسیر Redirect را از یک Global Variable دریافت می‌کند.

const nextPage = window.nextPage || "/home";

بعد:

location.assign(nextPage);

اگر مقدار nextPage از منبع قابل‌اعتماد نیامده باشد، DOM Clobbering می‌تواند در زنجیره تصمیم‌گیری دخالت کند.

پیامد ممکن است Open Redirect باشد.

Open Redirect می‌تواند برای:

Phishing

Login Flow Abuse

OAuth Confusion

یا هدایت User به Domain غیرقابل‌اعتماد

استفاده شود.

راهکار بهتر این است که Redirect Destination از Allowlist معتبر ساخته شود.

برای مثال:

const allowedRoutes = new Set([
    "/home",
    "/profile",
    "/settings"
]);

function safeRedirect(route) {
    const destination = allowedRoutes.has(route)
        ? route
        : "/home";

    location.assign(destination);
}

حتی اگر Input تغییر کند، تنها Route مجاز استفاده می‌شود.

Dynamic Script Loading و DOM Clobbering

خطر مهم‌تری زمانی شکل می‌گیرد که Variable قابل‌Clobber شدن برای ساخت Script URL استفاده شود.

مثلاً Application به شکل مفهومی چنین کند:

const source = config.scriptUrl;

const script = document.createElement("script");
script.src = source;
document.body.appendChild(script);

اگر config یا scriptUrl از فضای نامی دریافت شوند که DOM می‌تواند روی آن اثر بگذارد، Application ممکن است Resource غیرمنتظره‌ای بارگذاری کند.

OWASP دقیقاً Configurationهایی مانند URL دریافت Remote Content یا Script Source را از نمونه‌های حساس DOM Clobbering معرفی می‌کند.

راهکار امن:

Sourceها را ثابت یا Allowlist کنید.

از Configuration داخلی Module استفاده کنید.

CSP مناسب فعال کنید.

Type و Protocol URL را Validation کنید.

و هیچ URL کنترل‌شده توسط DOM را مستقیماً برای Script Loading استفاده نکنید.

نقش Content Security Policy در مقابله با DOM Clobbering

Content Security Policy یا CSP می‌تواند اثر بعضی سناریوهای DOM Clobbering را کاهش دهد.

برای نمونه اگر Attack Chain در نهایت نیازمند Load کردن Script از Domain غیرمجاز باشد، یک script-src محدود می‌تواند مانع آن شود.

اما CSP درمان کامل DOM Clobbering نیست.

OWASP نیز تأکید می‌کند CSP تنها بعضی Variantها را Mitigate می‌کند. اگر JavaScript از قبل موجود در سایت خودش Gadget مناسبی برای سوءاستفاده فراهم کند، CSP الزاماً مانع آن نخواهد شد.

بنابراین:

CSP ≠ Fix DOM Clobbering

CSP یک لایه Defense in Depth است.

کنترل اصلی باید Secure Coding باشد.

HTML Sanitizer چه نقشی دارد؟

اگر برنامه User-Generated HTML می‌پذیرد، Sanitization اهمیت بسیار زیادی دارد.

Sanitizer باید نه تنها <script> و Event Handlerهای ناامن را بررسی کند، بلکه ریسک Attributeهای Named مانند id و name را نیز در نظر بگیرد.

OWASP استفاده از Sanitizerهای معتبر مانند DOMPurify را توصیه می‌کند.

اما نکته مهم این است:

Sanitizer باید با Configuration مناسب استفاده شود.

صرف اینکه برنامه از یک Library Sanitization استفاده می‌کند به معنی پوشش تمام DOM Clobberingها نیست.

DOMPurify و DOM Clobbering

DOMPurify یکی از Libraryهای شناخته‌شده برای Sanitization HTML است.

OWASP توضیح می‌دهد که DOMPurify به‌صورت پیش‌فرض با گزینه SANITIZE_DOM بخشی از Collisionهای مربوط به DOM Built-inها را کنترل می‌کند.

برای محافظت قوی‌تر در برابر Named Propertyهای سفارشی، گزینه:

SANITIZE_NAMED_PROPS: true

قابل استفاده است.

نمونه:

const clean = DOMPurify.sanitize(
    untrustedHTML,
    {
        SANITIZE_NAMED_PROPS: true
    }
);

این تنظیم Namespace مربوط به id و name را ایزوله‌تر می‌کند تا احتمال Collision با متغیرهای Application کاهش پیدا کند.

البته قبل از فعال‌سازی چنین گزینه‌ای باید Compatibility Application تست شود؛ زیرا تغییر Named Properties ممکن است روی CSS، Link Fragmentها یا JavaScript قدیمی اثر بگذارد.

آیا حذف id و name بهترین راه است؟

اگر Application به این Attributeها احتیاج ندارد، حذف آن‌ها از User-Generated HTML می‌تواند روش قدرتمندی باشد.

اما همیشه عملی نیست.

Rich Text Content ممکن است برای:

Anchor Navigation

Accessibility

Form Labels

Fragment Links

یا Internal Linking

به ID نیاز داشته باشد.

در این شرایط Namespace Isolation راهکار بهتری است.

مثلاً تمام Named Properties محتوای User با Prefix مشخص ذخیره شوند:

user-content-

در نتیجه:

profile

به:

user-content-profile

تبدیل شود.

این روش احتمال Collision با Variableهای Application را کاهش می‌دهد.

Sanitizer API مرورگر

Browserها نیز به سمت APIهای Built-in برای Sanitization حرکت کرده‌اند.

OWASP اشاره می‌کند Sanitizer API در Configuration پیش‌فرض الزاماً DOM Clobbering را به طور کامل متوقف نمی‌کند و در صورت استفاده باید Attributeهای حساس مانند id و name براساس نیاز Application کنترل شوند.

قاعده کلی:

Sanitizer امن است فقط زمانی که Threat Model و Configuration آن با Application سازگار باشد.

چرا استفاده از let و const بهتر است؟

یکی از راهکارهای مهم JavaScript مدرن کاهش وابستگی به Global Namespace است.

استفاده از:

let
const

در Scope مناسب بهتر از ایجاد Globalهای ضمنی است.

برای نمونه:

const config = {...};

داخل Module یا Function Scope کمتر در معرض Named Global Collision قرار می‌گیرد.

در مقابل کد قدیمی ممکن است ناخواسته Global ایجاد کند.

OWASP نیز استفاده از Explicit Variable Declaration، Local Scope و Strict Mode را از کنترل‌های پیشنهادی DOM Clobbering معرفی می‌کند.

Strict Mode چه کمکی می‌کند؟

Strict Mode برخی رفتارهای مبهم JavaScript را محدود می‌کند.

برای مثال از ایجاد ناخواسته Global Variable در برخی شرایط جلوگیری می‌کند.

در Scriptهای سنتی:

"use strict";

و در ES Moduleها Strict Mode به‌صورت پیش‌فرض فعال است.

Strict Mode به تنهایی DOM Clobbering را از بین نمی‌برد.

اما احتمال اینکه کد Application ناخواسته Global State ایجاد کند را کاهش می‌دهد.

بنابراین یک کنترل مکمل است.

ES Modules و کاهش سطح حمله

استفاده از ES Modules یکی از بهترین تغییرات معماری برای Frontend مدرن است.

در Module:

const settings = {...};

به‌صورت خودکار Property روی window ایجاد نمی‌کند.

این جداسازی Namespace احتمال Collision با DOM Named Properties را کاهش می‌دهد.

برای برنامه‌های جدید بهتر است:

Configuration

Helperها

Security Logic

و Business State

داخل Moduleها نگهداری شوند.

نه به شکل:

window.app
window.config
window.security

Type Checking؛ یکی از مهم‌ترین دفاع‌ها

یکی از ویژگی‌های DOM Clobbering این است که Value مورد انتظار ممکن است ناگهان Type متفاوتی داشته باشد.

Developer انتظار String دارد.

اما Value تبدیل به Element می‌شود.

یا Object مورد انتظار تبدیل به HTMLCollection می‌شود.

به همین دلیل Type Checking بسیار مؤثر است.

مثلاً اگر URL انتظار می‌رود:

if (typeof candidate !== "string") {
    throw new TypeError("Invalid configuration");
}

اگر DOM Element انتظار می‌رود:

if (!(value instanceof HTMLElement)) {
    return;
}

OWASP نیز Type Checking را از Secure Coding Guidelines اصلی برای مقابله با DOM Clobbering معرفی کرده است.

نکته مهم:

در Security-Sensitive Code نباید JavaScript Coercion را جای Validation قرار داد.

Object.freeze چه کمکی می‌کند؟

برای Configuration حساس می‌توان از:

Object.freeze()

استفاده کرد.

مثلاً:

const config = Object.freeze({
    apiOrigin: "https://api.example.com",
    uploadPath: "/upload"
});

این کار مانع تغییر مستقیم Propertyهای Object می‌شود.

OWASP Freezing Sensitive DOM Objects یا Objectهای حساس را یکی از Mitigationهای ممکن معرفی می‌کند، اما اشاره دارد تعیین تمام Objectهایی که باید Freeze شوند همیشه آسان نیست.

بنابراین Object.freeze کنترل تکمیلی است و جای معماری درست را نمی‌گیرد.

Encapsulation

هرچه State برنامه عمومی‌تر باشد، Attack Surface بیشتر می‌شود.

Encapsulation یعنی State فقط در بخشی که به آن نیاز دارد در دسترس باشد.

برای مثال:

class ApplicationConfig {
    #apiURL = "/api";

    getAPIURL() {
        return this.#apiURL;
    }
}

Private Field مستقیماً از فضای DOM قابل دسترسی نیست.

در پروژه‌های بزرگ استفاده از:

Module

Class

Closure

Private Field

و Dependency Injection

باعث کاهش Global Mutable State می‌شود.

آیا نام‌های تصادفی راهکار مناسبی هستند؟

استفاده از نام‌های Unique می‌تواند احتمال Collision اتفاقی را کاهش دهد.

اما نباید تنها کنترل امنیتی باشد.

اگر Application همچنان از window برای State حساس استفاده کند، Random Naming فقط مشکل را پنهان می‌کند.

OWASP استفاده از نام‌های Unique را به‌عنوان یکی از تکنیک‌های کمکی پیشنهاد می‌کند، اما Secure Scope و Validation همچنان ضروری‌اند.

DOM Clobbering در Applicationهای Single Page

SPAها معمولاً JavaScript زیادی در Client اجرا می‌کنند.

اگر Framework State Management مناسبی داشته باشد، Global Window Dependency کمتر می‌شود.

اما Codeهای Legacy یا Integrationهای Third-Party ممکن است همچنان از Global Variables استفاده کنند.

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

Legacy Plugin

Inline Script

Third-Party Widget

Rich Text

User-Generated HTML

Dynamic Script Loader

Global Configuration Object

Migration از jQuery Code قدیمی

حتی برنامه React، Vue یا Angular نیز اگر بخشی از کد آن از:

window.someConfig

استفاده کند، ذاتاً از DOM Clobbering مصون نیست.

Framework Security جای Secure Coding را نمی‌گیرد.

DOM Clobbering در React

React به‌طور پیش‌فرض Text را هنگام Rendering Escape می‌کند که بسیاری از HTML Injectionها را کاهش می‌دهد.

اما اگر Application از:

dangerouslySetInnerHTML

استفاده کند و HTML ورودی به‌درستی Sanitize نشده باشد، Markup کنترل‌شده می‌تواند وارد DOM شود.

در چنین حالتی DOM Clobbering دوباره وارد Threat Model می‌شود.

راهکار:

از HTML Raw تا حد امکان استفاده نکنید.

در صورت نیاز، از Sanitizer معتبر استفاده کنید.

id و name را براساس Policy کنترل کنید.

Global Variableهای امنیتی روی window نسازید.

DOM Clobbering در Vue و Angular

Vue و Angular نیز Mechanismهای Sanitization و Template Binding خود را دارند.

اما استفاده از Raw HTML Rendering یا Bypass کردن Sanitization می‌تواند همان مسئله را ایجاد کند.

قاعده عمومی مستقل از Framework است:

Untrusted HTML
+
Named Properties
+
Unsafe JavaScript
=
Potential DOM Clobbering

هیچ Frameworkی نمی‌تواند کدی را که عمداً Security Boundaryها را دور می‌زند به‌صورت جادویی امن کند.

DOM Clobbering در WordPress

DOM Clobbering برای سایت‌های WordPress نیز موضوع قابل توجهی است، به‌خصوص زمانی که Pluginها یا Themeها JavaScript سفارشی زیادی دارند.

WordPress Core در حالت معمول بر مبنای DOM Clobbering طراحی نشده است، اما اکوسیستم WordPress بسیار گسترده است و Pluginها می‌توانند رفتار Client-Side متفاوتی داشته باشند.

ریسک می‌تواند در شرایط زیر افزایش پیدا کند:

Commentهای حاوی HTML

Custom HTML Block

Page Builder

Rich Text Editor

Frontend Profile

Forum Plugin

Chat Plugin

User-Generated Content

Themeهای دارای JavaScript قدیمی

Pluginهای Frontend که Configuration را روی window ذخیره می‌کنند.

WordPress Pluginها چه چیزی را باید بررسی کنند؟

Developer افزونه باید مشخص کند آیا User با سطح دسترسی پایین می‌تواند Markup وارد Frontend کند یا خیر.

سپس بررسی شود:

آیا id و name آزاد هستند؟

آیا HTML با wp_kses() یا مکانیزم مناسب محدود می‌شود؟

آیا JavaScript از Global Variable استفاده می‌کند؟

آیا Script Source یا Redirect از Object روی window گرفته می‌شود؟

آیا Raw HTML بعداً با JavaScript دوباره Parse می‌شود؟

آیا Plugin از Library Sanitization قدیمی استفاده می‌کند؟

ترکیب چند ضعف کوچک ممکن است به Vulnerability واقعی تبدیل شود.

آیا wp_kses به تنهایی کافی است؟

wp_kses() یکی از ابزارهای اصلی WordPress برای محدودسازی HTML است.

اما Policy واقعی باید با Context سایت مطابقت داشته باشد.

اگر Application اجازه Attributeهایی بدهد که برای DOM Clobbering مهم هستند و JavaScript نیز الگوی ناامن داشته باشد، Sanitization عمومی HTML لزوماً تمام Risk را حذف نمی‌کند.

امنیت باید بین:

Server-Side Sanitization

Frontend Architecture

JavaScript Scope

CSP

و Validation

تقسیم شود.

تأثیر DOM Clobbering چه می‌تواند باشد؟

Impact به Gadget موجود در JavaScript بستگی دارد.

DOM Clobbering به خودی خود Impact ثابتی ندارد.

در یک سایت ممکن است فقط باعث JavaScript Error شود.

در سایت دیگر ممکن است Redirect را تغییر دهد.

و در یک Application حساس‌تر می‌تواند به XSS Chain منجر شود.

پیامدهای احتمالی شامل:

تغییر رفتار Client-Side

اختلال در Form

Open Redirect

تغییر Resource URL

بارگذاری Resource غیرمنتظره

دستکاری Configuration

دور زدن برخی Logicهای Frontend

DOM-Based XSS Chain

اختلال در Feature Detection

یا Denial of Service در سطح رابط کاربری

است.

آیا DOM Clobbering می‌تواند احراز هویت را دور بزند؟

نباید Authentication یا Authorization واقعی به JavaScript Frontend وابسته باشد.

اگر Server دسترسی را به‌درستی کنترل کند، تغییر Variable سمت Client نباید مجوز واقعی ایجاد کند.

اما برخی Applicationها اشتباهاً Logicهای حساس را در Client نگه می‌دارند.

مثلاً:

if (window.isAdmin) {
    showAdminFeature();
}

حتی اگر چنین منطقی Clobber شود، Server باید مجدداً Permission را بررسی کند.

اصل مهم:

Frontend Authorization هرگز Security Boundary نهایی نیست.

DOM Clobbering یکی از دلایل دیگری است که نشان می‌دهد چرا Server-Side Authorization ضروری است.

نقش Same-Origin Policy

Same-Origin Policy بسیاری از دسترسی‌های Cross-Origin را محدود می‌کند، اما DOM Clobbering معمولاً داخل همان Document اتفاق می‌افتد.

مهاجم تلاش می‌کند Markup را وارد صفحه Target کند.

پس SOP به تنهایی آن را متوقف نمی‌کند.

کنترل اصلی در اینجا:

Input Sanitization

Named Property Policy

و Secure JavaScript

است.

نقش Trusted Types

Trusted Types بیشتر برای کاهش DOM XSS و جلوگیری از ورود String غیرقابل‌اعتماد به برخی DOM Sinkها طراحی شده است.

استفاده از Trusted Types می‌تواند سطح بعضی Attack Chainهای DOM Clobbering را کاهش دهد؛ خصوصاً زمانی که نتیجه در نهایت باید به Sinkهای HTML یا Script وارد شود.

اما Trusted Types نیز مشکل Named Property Collision را به تنهایی حل نمی‌کند.

این کنترل نیز باید بخشی از Defense in Depth باشد.

Fail Secure در Client-Side Logic

اگر JavaScript یک Configuration غیرمنتظره دریافت کرد، بهتر است به حالت امن برود.

برای مثال:

if (typeof config.apiURL !== "string") {
    throw new Error("Invalid application configuration");
}

نه اینکه تلاش کند Value را به String تبدیل کند و ادامه دهد.

این رفتار Fail Closed یا Fail Secure است.

مثلاً اگر Script URL معتبر نیست:

Script بارگذاری نشود.

اگر Redirect معتبر نیست:

به Route ثابت داخلی بروید.

اگر Object Config Type اشتباه دارد:

Feature متوقف شود.

Logging و Monitoring

DOM Clobbering عمدتاً Client-Side است و تشخیص آن از Server Log دشوارتر از Injectionهای Server-Side است.

اما Monitoring همچنان مفید است.

می‌توان موارد زیر را ثبت یا Monitor کرد:

CSP Violation Report

Frontend Exception

Unexpected Navigation

Script Load Failure

Client Error Telemetry

Sanitization Rejection

Markup Validation Failure

تعداد زیاد HTML Sanitization Event

البته Telemetry نباید اطلاعات خصوصی User یا Secretها را بدون ضرورت ارسال کند.

چگونه DOM Clobbering را در Code Review پیدا کنیم؟

در Code Review بهتر است ابتدا Patternهای خطرناک جستجو شوند.

استفاده مستقیم از window

مواردی مانند:

window.config
window.redirect
window.url
window.settings

باید بررسی شوند.

سؤال:

این Property کجا ایجاد می‌شود؟

آیا Type آن Validation می‌شود؟

آیا Named DOM Element می‌تواند با آن برخورد کند؟

استفاده مستقیم از document Named Properties

Patternهایی شبیه:

document.something

برای State سفارشی باید بررسی شوند.

Logical OR روی Global Variable

الگوی:

window.value || defaultValue

می‌تواند خطرناک باشد، زیرا وجود هر Truthy Object می‌تواند Default را کنار بزند.

بهتر است Type و Format دقیق بررسی شود.

Dynamic Script Source

هر کدی که:

script.src = variable;

دارد باید Trace شود.

Redirect

هر کدی که Variable را وارد:

location
location.href
location.assign()

می‌کند نیازمند Validation است.

Raw HTML

موارد:

innerHTML
insertAdjacentHTML

باید از نظر Source و Sanitization بررسی شوند.

تست امنیت DOM Clobbering

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

هدف تست دفاعی این نیست که XSS واقعی روی کاربران ایجاد شود.

هدف شناسایی Collision و Data Flow ناامن است.

فرایند مناسب می‌تواند چنین باشد:

  1. محل‌های ورود User-Generated HTML شناسایی شوند.
  2. مشخص شود چه Tagها و Attributeهایی باقی می‌مانند.
  3. استفاده از id و name بررسی شود.
  4. Global Variableها استخراج شوند.
  5. Propertyهای window و document بررسی شوند.
  6. Script Source و Redirectها Trace شوند.
  7. Type Checking بررسی شود.
  8. Sanitizer Configuration Audit شود.
  9. CSP بررسی شود.
  10. رفتار Browserهای اصلی مقایسه شود.

PortSwigger ابزار DOM Invader را نیز برای شناسایی DOM Clobbering در محیط تست ارائه می‌کند و در نسخه‌های فعلی Burp می‌توان این نوع بررسی را جداگانه فعال کرد.

این ابزار باید فقط در محیط مجاز استفاده شود.

تفاوت رفتار مرورگرها

DOM Clobbering به رفتار استاندارد و Legacy Browserها وابسته است.

بعضی جزئیات Property Resolution ممکن است میان Browserها تفاوت داشته باشد.

به همین دلیل Vulnerabilityای ممکن است در یک Browser قابل مشاهده باشد اما در Browser دیگری متفاوت رفتار کند.

PortSwigger نیز در برخی آزمایشگاه‌های DOM Clobbering خود به Browser-specific بودن بعضی رفتارها اشاره می‌کند.

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

«اگر در یک Browser کار نمی‌کند، امن است.»

کد باید براساس Secure Design نوشته شود، نه رفتار اتفاقی یک Browser. مهم‌ترین راهکارهای جلوگیری از DOM Clobbering

مهم‌ترین راهکارهای جلوگیری از DOM Clobbering

راهکار مؤثر یک کنترل واحد نیست.

بهترین نتیجه از Defense in Depth حاصل می‌شود.

HTML ورودی را Sanitize کنید

هر HTML کنترل‌شده توسط User باید قبل از وارد شدن به DOM با Sanitizer معتبر پردازش شود.

Policy باید id و name را نیز در نظر بگیرد.

Raw HTML را محدود کنید

اگر Feature بدون HTML قابل پیاده‌سازی است، Text Plain انتخاب امن‌تری است.

Global Variable را کاهش دهید

State برنامه را در:

Modules

Closures

Classes

و Local Scope

نگه دارید.

از window و document برای Configuration استفاده نکنید

Objectهای Global یکی از اصلی‌ترین Targets DOM Clobbering هستند.

Type Validation انجام دهید

قبل از هر عملیات حساس، Type واقعی Value بررسی شود.

URL را Allowlist کنید

URLهای Redirect، API و Script نباید صرفاً براساس String دریافتی پذیرفته شوند.

CSP فعال کنید

CSP می‌تواند بعضی Attack Chainها را مسدود کند.

Strict Mode و ES Modules استفاده کنید

Global State ناخواسته را کاهش می‌دهند.

Permission را سمت Server بررسی کنید

هیچ Logic امنیتی نباید تنها به Client وابسته باشد.

Dependencyها را به‌روز نگه دارید

Sanitizerها و Frontend Libraryهای قدیمی می‌توانند رفتار یا Bugهای امنیتی شناخته‌شده داشته باشند.

اشتباهات رایج درباره DOM Clobbering

تصور اینکه حذف script کافی است

ممکن است <script> کاملاً Block شده باشد اما Markup دارای id یا name هنوز DOM را تحت تأثیر قرار دهد.

اعتماد به CSP به‌عنوان راهکار کامل

CSP فقط بعضی Attack Chainها را محدود می‌کند.

استفاده گسترده از window

قرار دادن تمام Configurationها روی window سطح Collision را بالا می‌برد.

نبود Type Checking

اگر Program String انتظار دارد ولی Element دریافت کند، نباید ادامه دهد.

Sanitization بدون Policy

استفاده از Sanitizer با Configuration نامناسب ممکن است Named Properties موردنظر مهاجم را حفظ کند.

استفاده از Client-Side Authorization

Client باید UI را مدیریت کند، نه Security Permission نهایی را.

نام‌های بسیار عمومی

نام‌هایی مانند:

config
settings
url
redirect
data
user

احتمال Collision بیشتری دارند.

استفاده از Legacy JavaScript

Global Variableهای زیاد، Inline Script و Functionهای قدیمی مدیریت Namespace را سخت‌تر می‌کنند.

چک‌لیست امنیتی DOM Clobbering

پیش از انتشار Application بررسی کنید:

  1. آیا User می‌تواند HTML وارد سایت کند؟
  2. آیا id و name در HTML کاربر مجاز هستند؟
  3. آیا Sanitizer معتبر استفاده می‌شود؟
  4. آیا DOMPurify با Configuration متناسب استفاده شده است؟
  5. آیا Application از window برای Configuration استفاده می‌کند؟
  6. آیا Property سفارشی روی document وجود دارد؟
  7. آیا Global Variableهای Legacy وجود دارند؟
  8. آیا ES Module استفاده شده است؟
  9. آیا Strict Mode فعال است؟
  10. آیا URLها قبل از استفاده Validation می‌شوند؟
  11. آیا Redirectها Allowlist دارند؟
  12. آیا Dynamic Script Loading وجود دارد؟
  13. آیا Script URL قابل‌کنترل است؟
  14. آیا Valueها Type Checked می‌شوند؟
  15. آیا Form Controlها نام مشابه APIهای Built-in دارند؟
  16. آیا Raw HTML وارد DOM می‌شود؟
  17. آیا CSP مناسب فعال است؟
  18. آیا Trusted Types در Applicationهای حساس بررسی شده است؟
  19. آیا Frontend Authorization سمت Server نیز enforce می‌شود؟
  20. آیا Dependencyهای Frontend به‌روز هستند؟
  21. آیا Rich Text Editor Policy بررسی شده است؟
  22. آیا Third-Party Widgetها Audit شده‌اند؟
  23. آیا WordPress Pluginهای دارای Custom HTML بررسی شده‌اند؟
  24. آیا رفتار در Browserهای اصلی تست شده است؟
  25. آیا CSP Violation و Frontend Exception مانیتور می‌شوند؟
معماری پیشنهادی برای جلوگیری از DOM Clobbering

معماری پیشنهادی برای جلوگیری از DOM Clobbering

یک جریان امن برای User-Generated Content می‌تواند چنین باشد:

User Input
   ↓
Server-side Validation
   ↓
HTML Sanitization
   ↓
Named Attribute Policy
   ↓
Database
   ↓
Output
   ↓
Frontend Sanitization در صورت نیاز
   ↓
DOM

در کنار آن JavaScript باید معماری جداگانه‌ای داشته باشد:

Application Module
   ↓
Local Configuration
   ↓
Type Validation
   ↓
URL / Value Allowlist
   ↓
Sensitive Operation

این دو Flow نباید در Global Namespace به هم متصل شوند.

یعنی:

User HTML
   ↓
window.config
   ↓
Sensitive JavaScript

نباید معماری Application باشد.

نمونه کدنویسی ناامن

الگوی زیر از دید Secure Coding مشکوک است:

const config =
    window.appConfig ||
    {
        endpoint: "/api"
    };

fetch(config.endpoint);

دلایل:

window محل Shared Global State است.

Type appConfig بررسی نمی‌شود.

Type endpoint بررسی نمی‌شود.

URL Allowlist ندارد.

Fallback تنها براساس Truthy بودن تصمیم می‌گیرد.

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

const APP_CONFIG = Object.freeze({
    endpoint: "/api"
});

function getEndpoint() {
    const endpoint = APP_CONFIG.endpoint;

    if (typeof endpoint !== "string") {
        throw new TypeError("Invalid endpoint");
    }

    if (!endpoint.startsWith("/")) {
        throw new Error("External endpoints are not allowed");
    }

    return endpoint;
}

fetch(getEndpoint());

در این الگو:

DOM تعیین‌کننده Configuration نیست.

Value Local است.

Object Freeze شده است.

Type بررسی می‌شود.

URL Policy وجود دارد.

Defense چندلایه است.

DOM Clobbering در چرخه Secure Development

بهتر است کنترل این Vulnerability فقط به Penetration Test نهایی موکول نشود.

مرحله طراحی

مشخص کنید کجا HTML از User دریافت می‌شود.

Trust Boundaryها را تعیین کنید.

تصمیم بگیرید آیا Raw HTML واقعاً لازم است.

مرحله توسعه

از Module Scope استفاده کنید.

Global Variable را محدود کنید.

Sanitizer را به‌صورت Centralized پیاده کنید.

Code Review

Named Property Access و window Usage بررسی شود.

CI/CD

Dependencyهای Sanitizer و Framework Scan شوند.

تست امنیت

DOM Source و Sink بررسی شوند.

Production

CSP Reporting و Frontend Error Monitoring فعال باشد.

این رویکرد بسیار مؤثرتر از Patch کردن یک Payload خاص است.

سؤالات متداول درباره DOM Clobbering

DOM Clobbering چیست؟

DOM Clobbering تکنیکی است که از رفتار Named Properties مرورگر استفاده می‌کند تا عناصر HTML دارای id یا name با متغیرها یا Propertyهای JavaScript تداخل ایجاد کنند. در صورت وجود کد ناامن، این وضعیت می‌تواند رفتار Application را تغییر دهد.

آیا DOM Clobbering همان XSS است؟

خیر. DOM Clobbering و XSS Vulnerabilityهای متفاوتی هستند. DOM Clobbering می‌تواند بخشی از یک زنجیره باشد که در نهایت به DOM XSS منجر می‌شود، اما الزاماً باعث اجرای JavaScript نمی‌شود.

آیا برای DOM Clobbering نیاز به تزریق JavaScript است؟

معمولاً خیر. یکی از ویژگی‌های مهم DOM Clobbering این است که در بعضی شرایط تنها تزریق HTML کافی است.

چرا id و name مهم هستند؟

Browser از برخی Attributeهای id و name برای ایجاد Named Properties روی Objectهایی مانند window و document استفاده می‌کند. همین رفتار امکان Namespace Collision را فراهم می‌کند.

آیا رفتار Named Properties یک Bug مرورگر است؟

خیر. بخش مهمی از این رفتار در استاندارد HTML تعریف شده و برای سازگاری با وب قدیمی حفظ شده است.

آیا DOM Clobbering فقط در Chrome رخ می‌دهد؟

خیر. اصل Named Property Access در مرورگرهای مختلف وجود دارد، اما جزئیات برخی تکنیک‌ها می‌تواند Browser-specific باشد.

آیا Sanitizer از DOM Clobbering جلوگیری می‌کند؟

Sanitizer معتبر می‌تواند ریسک را کاهش دهد، اما Configuration آن اهمیت دارد. Policy باید Attributeهایی مانند id و name و Namespace Collision را نیز در نظر بگیرد.

آیا DOMPurify در برابر DOM Clobbering محافظت می‌کند؟

DOMPurify مکانیزم‌هایی برای کاهش DOM Clobbering دارد. برای ایزوله‌سازی قوی‌تر Named Properties سفارشی می‌توان براساس نیاز Application گزینه SANITIZE_NAMED_PROPS را بررسی کرد.

آیا CSP مشکل را حل می‌کند؟

خیر. CSP می‌تواند برخی Attack Chainها، به‌خصوص Load شدن Script غیرمجاز را محدود کند، اما خود Named Property Collision را حذف نمی‌کند.

آیا استفاده از let و const کافی است؟

خیر، اما استفاده از Scope مناسب و let و const احتمال ایجاد Global State ناخواسته را کاهش می‌دهد.

ES Module چه کمکی می‌کند؟

متغیرهای Module به‌صورت پیش‌فرض در Global Window Namespace قرار نمی‌گیرند. بنابراین سطح برخورد با Named DOM Properties کمتر می‌شود.

آیا Object.freeze جلوی DOM Clobbering را می‌گیرد؟

در بعضی Configuration Objectهای حساس مفید است، اما راهکار جامع نیست. Global State و Named Property Access همچنان باید حذف یا Validation شوند.

DOM Clobbering چه تأثیری دارد؟

Impact می‌تواند از JavaScript Error ساده تا Open Redirect، دستکاری Resource URL یا در بعضی شرایط XSS متفاوت باشد. شدت به Gadgetهای JavaScript موجود در Application بستگی دارد.

آیا سایت WordPress می‌تواند DOM Clobbering داشته باشد؟

بله. Theme یا Plugin دارای JavaScript ناامن و User-Generated HTML می‌تواند شرایط لازم را ایجاد کند. WordPress بودن سایت به تنهایی باعث Vulnerability یا مصونیت نمی‌شود.

آیا WAF جلوی DOM Clobbering را می‌گیرد؟

WAF ممکن است بعضی HTMLهای مشکوک را Block کند، اما مکانیزم DOM Clobbering در Browser اجرا می‌شود و WAF کنترل اصلی محسوب نمی‌شود.

چگونه DOM Clobbering سایت خود را بررسی کنیم؟

User-Generated HTML، Sanitizer Configuration، Attributeهای id و name، Global Variableهای window و document، Dynamic Script Loading، Redirectها و DOM Sinkهای حساس را بررسی کنید. Code Review و ابزارهای تست Client-Side مانند DOM Invader نیز در محیط مجاز می‌توانند کمک‌کننده باشند.

جمع‌بندی

DOM Clobbering یکی از آسیب‌پذیری‌های کمتر شناخته‌شده JavaScript است که نشان می‌دهد حتی رفتارهای قانونی و استاندارد Browser می‌توانند در ترکیب با طراحی ناامن به یک مشکل امنیتی تبدیل شوند.

ریشه اصلی DOM Clobbering وجود Named Property Access در HTML است.

عناصر دارای id یا name در برخی شرایط می‌توانند روی Property Resolution در window، document یا Objectهایی مانند Form اثر بگذارند.

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

مشکل زمانی ایجاد می‌شود که Application اجازه ورود HTML کنترل‌شده را بدهد و JavaScript نیز بدون Type Checking یا Validation به Named Properties اعتماد کند.

در چنین معماری‌ای مهاجم ممکن است بدون تزریق مستقیم JavaScript، Referenceهایی را که Application استفاده می‌کند تحت تأثیر قرار دهد.

اگر Value نهایی وارد Sink حساسی مانند Redirect، Dynamic Script Loading یا DOM Rendering شود، Impact می‌تواند از یک اختلال ساده فراتر برود.

مهم‌ترین راهکار جلوگیری از DOM Clobbering، حذف وابستگی JavaScript به Global DOM Namespace است.

Configuration و State باید در Moduleها، Scopeهای محلی یا Objectهای Encapsulated نگهداری شوند.

استفاده از window و document برای ذخیره داده‌های حساس یا Configuration باید به حداقل برسد.

در Applicationهایی که User-Generated HTML دارند، HTML Sanitization باید علاوه بر Script و Event Handlerها، Named Propertyهای id و name را نیز در Threat Model در نظر بگیرد.

DOMPurify، Sanitizerهای معتبر، Namespace Isolation و Policy دقیق می‌توانند سطح خطر را کاهش دهند.

در کنار آن CSP، Trusted Types، Type Checking، Strict Mode، ES Modules و Object.freeze لایه‌های دفاعی مکمل ایجاد می‌کنند.

همچنین باید توجه داشت که Frontend هرگز نباید تنها محل Authorization باشد.

حتی اگر DOM Clobbering بتواند State رابط کاربری را تغییر دهد، Server باید تمام Permissionهای حساس را مستقل بررسی کند.

بهترین دفاع در برابر DOM Clobbering نه Block کردن چند نام خاص، بلکه یک معماری مدرن JavaScript است که در آن User HTML و Application State دو فضای جداگانه داشته باشند.

هرچه Global State کمتر، Type Validation دقیق‌تر و Sanitization هدفمندتر باشد، فرصت سوءاستفاده از Named Properties نیز کمتر خواهد شد.

DOM Clobbering نمونه خوبی از یک اصل اساسی امنیت وب است:

هر رفتاری که Browser برای راحتی Developer فراهم می‌کند، اگر بدون شناخت Trust Boundary استفاده شود، می‌تواند به بخشی از سطح حمله تبدیل شود.

مطالب مرتبط