SharedArrayBuffer بالاخره دوباره در مرورگر کار میکند، اما تنها زمانی که صفحه از نظر cross-origin ایزوله (isolated) باشد؛ وضعیتی که مستلزم دو هدر پاسخ (response header) است. اضافه کردن این هدرها مرا مجبور کرد تمام اسکریپتهای شخص ثالث (third-party) سایت خود را حذف کنم؛ اقدامی که نحوه ساخت کل فرانتاند و دادههایی که از آن نشت میکند را بازطراحی کرد.
چرا این هدرها اهمیت دارند
SharedArrayBuffer امکان چندرشتهای (multithreading) واقعی را در جاوااسکریپت فراهم میکند که پیشنیاز اجرای ffmpeg در داخل یک تب است. مرورگرهای مدرن این ویژگی را پس از اقدامات مقابلهای با سبک Spectre دوباره فعال کردند، اما آن را به cross-origin isolation گره زدند. برای دستیابی به این ایزولاسیون، سرور باید این موارد را ارسال کند:
Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corp
هدر دوم، require-corp ، به مرورگر میگوید که هر منبع خارجی باید یا دارای هدر Cross-Origin-Resource-Policy باشد و یا با استفاده از CORS (Cross-Origin Resource Sharing) فراخوانی شود. اکثر سرویسهای شخص ثالث این هدرها را تنظیم نمیکنند، بنابراین اسکریپتها، فونتها و iframeهای آنها مستقیماً مسدود میشوند.
آنچه با فعال شدن ایزولاسیون از کار افتاد
لحظهای که هدرها فعال شدند، سلسلهای از شکستها ظاهر شد:
- Analytics – اکثر ارائهدهندگان کد رهگیری خود را با یک
<script>ساده بارگذاری میکنند که یک درخواست no-CORS ارسال میکند. بدون هدر CORP، درخواست رد میشود و در نتیجه ردیاب هرگز اجرا نمیشود. - Google Fonts – استایلشیت از
fonts.googleapis.comبدون CORS فراخوانی میشود. مرورگر آن را نادیده میگیرد و صفحه بدون تایپوگرافی سفارشی خود باقی میماند. - Embedded media – iframeهای یوتیوب و اسکریپتهای ویجت فاقد CORP هستند، بنابراین رندر نمیشوند.
- OAuth pop-ups – رابطه
window.openerتوسط سیاست سختگیرانه same-origin شکسته میشود و جریان معمول ورود از طریق پاپآپ مختل میگردد.
به طور خلاصه، هر دارایی (asset) که به یک دامنه شخص ثالث وابسته بود، ناپدید شد، مگر اینکه آن دامنه از رژیم هدرهای جدید پیروی میکرد.
بازسازی بدون واسطهها
با مواجهه با یک سایت از کار افتاده، من پشته (stack) فرانتاند را حول محور داراییهای میزبانیشده توسط خودم (self-hosted) بازنویسی کردم:
- فونتها و تصاویر اکنون از مبدأ (origin) خود من سرویسدهی میشوند و نیاز به استایلشیتهای خارجی را از بین میبرند.
- Data APIs بر پایه یک بکاند خصوصی که خودم کنترل میکنم ساخته شدهاند، بنابراین هر درخواست در داخل دامنه من باقی میماند.
- Analytics به یک Cloudflare Worker کوچک تبدیل شد که رویدادهای
POSTرا میپذیرد و آنها را در یک باکت (bucket) خصوصی ذخیره میکند. سمت کلاینت فقط شامل ده-دوازده خط کدfetchاست. - ابزارهای گزارش خطا و بازپخش نشست (session replay) مانند Sentry کاملاً حذف شدند؛ اکنون هر کرش (crash) در نقطه پایانی (endpoint) خود من ثبت میشود.
اگر همچنان به یک منبع خارجی نیاز باشد، تنها راه عملی این است که آن را از طریق سروری که متعلق به خودتان است پروکسی کنید و قبل از اینکه مرورگر آن را ببیند، هدر CORP لازم را به آن اضافه کنید.
دستاوردهای حریم خصوصی در مقابل هزینههای عملیاتی
مزیت فوری مشخص است: سایت دیگر دادههای استفاده را به شبکههای تبلیغاتی، ارائهدهندگان فونت یا پلتفرمهای ویدئویی نشت نمیدهد. تمام دادههای تلهمتری (telemetry) تحت کنترل من باقی میماند و هر زمان که بخواهم میتوانم آنها را حذف کنم. دستیابی به این سطح از حریم خصوصی با پشتههای معمول شخص ثالث دشوار است.
هزینه این کار، بار اضافی نگهداری است. میزبانی فونتها، مدیریت ذخیرهسازی تحلیلها و بهروز نگه داشتن یک پروکسی، وظایفی هستند که اکثر توسعهدهندگان آنها را به سرویسهای تخصصی برونسپاری میکنند. این رویکرد همچنین به معنای از دست دادن ویژگیهایی است که آن سرویسها ارائه میدهند؛ برای مثال، تجمیع خطاهای بلادرنگ (real-time) یا بصریسازیهای دقیق قیف فروش (funnel visualisations).
دیدگاه مقابل: آیا اکوسیستم سازگار خواهد شد؟
برخی استدلال میکنند که فروشندگان شخص ثالث در نهایت هدرهای مورد نیاز را اضافه خواهند کرد و پذیرش cross-origin isolation را بدون دردسر میکنند. تعداد کمی از آنها در حال حاضر این کار را انجام میدهند، اما اکثریت سرویسهای پرکاربرد هنوز این کار را نمیکنند. تا زمانی که اکوسیستم خود را به این سطح برساند، توسعهدهندگان باید تصمیم بگیرند که آیا مزیت حریم خصوصی بر تلاش مهندسی مورد نیاز برای میزبانی شخصی (self-host) میارزد یا خیر.
چگونه تأیید کنید که واقعاً ایزوله هستید
قبل از شروع بازنویسی، تأیید کنید که مرورگر صفحه شما را به عنوان ایزوله میبیند:
crossOriginIsolated // should be true
typeof SharedArrayBuffer // should be "function"
اگر هر یک از بررسیها با شکست مواجه شد، هدرها به درستی اعمال نمیشوند و SharedArrayBuffer در دسترس نخواهد بود.
گام بعدی برای توسعهدهندگان چیست؟
با تلاش اپلیکیشنهای وب بیشتر برای دستیابی به افزایش عملکردِ جاوااسکریپتِ چندرشتهای، فشار بر ارائهدهندگان شخص ثالث برای پذیرش CORP افزایش خواهد یافت. در این میان، هر پروژهای که به SharedArrayBuffer نیاز دارد، باید برای یک استراتژی میزبانی شخصیِ داراییها یا یک لایه پروکسی سبک برنامهریزی کند. همچنین، دنبال کردن یادداشتهای انتشار مرورگر (browser release notes) برای تغییرات در الزامات ایزولاسیون ضروری خواهد بود.
نکته کلیدی: فعالسازی جداسازی cross-origin برای دسترسی به SharedArrayBuffer، یک انتخاب دشوار را تحمیل میکند: حفظ سهولت استفاده از اسکریپتهای شخص ثالث، یا معاوضه آن با یک مدل حریم خصوصی سختگیرانهتر و تحت کنترل خود. این تصمیم هم معماری فنی و هم ردپای جریان داده (data-flow footprint) وبسایتهای مدرن را بازتعریف میکند.
