پیاده‌سازی CSP و اشکال‌زدایی «انواع مطمئن» در Chrome DevTools

Kateryna Prokopenko
Kateryna Prokopenko
Alfonso Castaño
Alfonso Castaño

اینجا ثبت‌نام کنید.

این پست وبلاگ درباره پیاده‌سازی پشتیبانی DevTools برای اشکال‌زدایی مشکلات «خط‌مشی امنیتی محتوا» (CSP) با کمک برگه مشکلات که اخیراً معرفی شده است است.

کار پیاده‌سازی درطول ۲ دوره کارآموزی انجام شد: ۱. درطول اولین آزمایش، چارچوب گزارش‌دهی عمومی را ساختیم و پیام‌های مشکل را برای ۳ مشکل نقض CSP طراحی کردیم. ۲. در طول دومی، مشکلات Trusted Type را در کنار برخی ویژگی‌های تخصصی DevTools برای اشکال‌زدایی Trusted Types اضافه کردیم.

«خط‌مشی امنیتی محتوا» چیست؟

خط‌مشی امنیتی محتوا (CSP) امکان محدود کردن برخی‌از رفتارها را در وب‌سایت برای افزایش امنیت فراهم می‌کند. برای مثال، می‌توان از CSP برای غیرمجاز کردن دستورگان‌های درون‌خطی یا غیرمجاز کردن eval استفاده کرد که هر دو سطح حمله را برای حملات اسکریپت بین‌سایتی (XSS) کاهش می‌دهند. برای آشنایی دقیق با CSP، اینجا را بخوانید.

یک CSP به‌خصوص جدید، خط‌مشی Trusted Types(TT) است که تجزیه‌وتحلیل پویایی را فعال می‌کند که می‌تواند به‌طور سیستماتیک از کلاس بزرگی از حملات تزریقی در وب‌سایت‌ها جلوگیری کند. برای دستیابی به این هدف، TT از وب‌سایت در نظارت بر کد جاوا اسکریپت آن پشتیبانی می‌کند تا فقط به انواع خاصی از چیزها اجازه دهد به سینک‌های DOM مانند innerHTML اختصاص داده شوند.

وب‌سایت می‌تواند با گنجاندن سرصفحه HTTP خاصی، خط‌مشی امنیتی محتوا را فعال کند. برای مثال، سرصفحه content-security-policy: require-trusted-types-for 'script'; trusted-types default خط‌مشی TT را برای صفحه فعال می‌کند.

هر خط‌مشی می‌تواند در یکی از این حالت‌ها عمل کند:

  • حالت اجرایی - که در آن هر نقض خط‌مشی یک خطا است،
  • حالت فقط گزارش - که پیام خطا را به‌عنوان هشدار گزارش می‌کند، اما باعث خرابی در صفحه وب نمی‌شود.

مشکلات اجرای خط‌مشی امنیتی محتوا در برگه مشکلات

هدف از این کار بهبود تجربه اشکال‌زدایی برای مشکلات CSP بود. هنگام بررسی مشکلات جدید، تیم DevTools تقریباً این فرایند را دنبال می‌کند:

  1. تعریف داستان‌های کاربر. مجموعه‌ای از داستان‌های کاربر را در DevTools سمت کاربر شناسایی کنید که نحوه بررسی مشکل توسط توسعه‌دهنده وب را پوشش می‌دهد.
  2. پیاده‌سازی فرانت‌اند. براساس داستان‌های کاربر، مشخص کنید کدام اطلاعات برای بررسی مشکل در بخش کاربری لازم است (برای مثال، درخواست مرتبط، نام کوکی، خطی در فایل html یا اسکریپت، و غیره).
  3. تشخیص مشکل. مکان‌هایی را در مرورگر که مشکل در Chrome قابل‌شناسایی است شناسایی کنید و مکان را برای گزارش مشکل، ازجمله اطلاعات مربوطه از مرحله (۲)، آماده کنید.
  4. مشکلات را ذخیره و نمایش دهید. مشکلات را در مکان مناسبی ذخیره کنید و پس‌از باز شدن DevTools، آن‌ها را دردسترس DevTools قرار دهید
  5. درحال طراحی نوشتار مشکلات. متن توضیحی‌ای ارائه دهید که به توسعه‌دهنده وب کمک کند مشکل را درک کند و مهم‌تر از آن، مشکل را برطرف کند

مرحله ۱: تعریف داستان‌های کاربر برای مشکلات CSP

قبل‌از اینکه کار پیاده‌سازی را شروع کنیم، سند طراحی با داستان‌های کاربر ایجاد کردیم تا بهتر متوجه شویم چه کاری باید انجام دهیم. برای مثال، داستان کاربر زیر را نوشتیم:


به‌عنوان توسعه‌دهنده‌ای که به‌تازگی متوجه شده است برخی‌از بخش‌های وب‌سایتش مسدود شده است، می‌خواهم:- - ...بدانم آیا «خط‌مشی امنیتی محتوا» دلیل مسدود شدن iframe / تصاویر در وب‌سایتم است یا نه - ...بدانم کدام دستورالعمل «خط‌مشی امنیتی محتوا» باعث مسدود شدن منبع خاصی شده است - ...بدانم چگونه «خط‌مشی امنیتی محتوا» وب‌سایتم را تغییر دهم تا منابعی که درحال‌حاضر مسدود شده‌اند نمایش داده شوند / js که درحال‌حاضر مسدود شده است اجرا شود.


برای کاوش این داستان کاربر، چند صفحه وب نمونه ساده ایجاد کردیم که نقض‌های CSP موردنظر ما را نشان می‌دادند و برای آشنایی با این فرایند، صفحات نمونه را کاوش کردیم. در اینجا چند نمونه از صفحه‌های وب آورده شده است (نسخه نمایشی را با زبانه مشکلات باز کنید):

بااستفاده از این فرایند، متوجه شدیم که مکان منبع مهم‌ترین بخش اطلاعات برای اشکال‌زدایی مشکلات CSP است. همچنین متوجه شدیم که پیدا کردن سریع iframe و درخواست مرتبط درصورت مسدود شدن منبع مفید است و پیوند مستقیم به عنصر HTML در پانل عناصر در DevTools نیز می‌تواند مفید باشد.

مرحله ۲: پیاده‌سازی فرانت‌اند

ما این اطلاعات آماری را به اولین پیش‌نویس اطلاعاتی تبدیل کردیم که می‌خواستیم ازطریق پروتکل Chrome DevTools‏ (CDP) در DevTools دردسترس قرار دهیم:

در زیر گزیده‌ای از third_party/blink/public/devtools_protocol/browser_protocol.pdl آمده است

 type ContentSecurityPolicyIssueDetails extends object
   properties
     # The url not included in allowed sources.
     optional string blockedURL
     # Specific directive that is violated, causing the CSP issue.
     string violatedDirective
     boolean isReportOnly
     ContentSecurityPolicyViolationType contentSecurityPolicyViolationType
     optional AffectedFrame frameAncestor
     optional SourceCodeLocation sourceCodeLocation
     optional DOM.BackendNodeId violatingNodeId

تعریف بالا اساساً ساختار داده JSON را کدگذاری می‌کند. این پروتکل به زبان ساده‌ای به‌نام PDL (زبان داده پروتکل) نوشته شده است. از PDL برای دو هدف استفاده می‌شود. ابتدا، از PDL برای تولید تعاریف TypeScript که DevTools front-end به آن متکی است استفاده می‌کنیم. برای مثال، تعریف PDL بالا میانای TypeScript زیر را تولید می‌کند:

export interface ContentSecurityPolicyIssueDetails {
  /**
  * The url not included in allowed sources.
  */
  blockedURL?: string;
  /**
  * Specific directive that is violated, causing the CSP issue.
  */
  violatedDirective: string;
  isReportOnly: boolean;
  contentSecurityPolicyViolationType: ContentSecurityPolicyViolationType;
  frameAncestor?: AffectedFrame;
  sourceCodeLocation?: SourceCodeLocation;
  violatingNodeId?: DOM.BackendNodeId;
}

دوم، و احتمالاً مهم‌تر از آن، ما یک کتابخانه C++‎ از تعریفی تولید می‌کنیم که تولید و ارسال این ساختارهای داده را از باطن C++‎ Chromium به پیشانی DevTools مدیریت می‌کند. بااستفاده از آن کتابخانه، می‌توان بااستفاده از قطعه کد C++‎ زیر، شیء ContentSecurityPolicyIssueDetails ایجاد کرد:

protocol::Audits::ContentSecurityPolicyIssueDetails::create()
  .setViolatedDirective(d->violated_directive)
  .setIsReportOnly(d->is_report_only)
  .setContentSecurityPolicyViolationType(BuildViolationType(
      d->content_security_policy_violation_type)))
  .build();

وقتی تصمیم گرفتیم کدام اطلاعات را دردسترس قرار دهیم، باید بررسی می‌کردیم که این اطلاعات را از کجای Chromium دریافت کنیم.

مرحله ۳: تشخیص مشکل

برای اینکه اطلاعات را در قالبی که در بخش آخر شرح داده شد برای «پروتکل Chrome DevTools»‏ (CDP) دردسترس قرار دهیم، باید جایی را که اطلاعات واقعاً در پس‌رانه دردسترس بود پیدا می‌کردیم. خوشبختانه، کد CSP ازقبل دارای یک گلوگاه بود که برای حالت فقط گزارش استفاده می‌شد و می‌توانستیم به آن متصل شویم: ContentSecurityPolicy::ReportViolation مشکلات را به یک نقطه پایانی گزارش‌دهی (اختیاری) گزارش می‌دهد که می‌تواند در سرصفحه CSP HTTP پیکربندی شود. بیشتر اطلاعاتی که می‌خواستیم گزارش کنیم ازقبل دردسترس بود، بنابراین برای کار کردن ابزار دقیق ما، تغییرات بزرگی در پس‌بخش لازم نبود.

مرحله ۴: ذخیره و نمایش مشکلات

یک پیچیدگی کوچک این است که ما همچنین می‌خواستیم مشکلاتی را که قبل‌از باز شدن DevTools رخ داده‌اند گزارش کنیم، مشابه نحوه مدیریت پیام‌های کنسول. این یعنی ما مشکلات را مستقیماً به میانای کاربری گزارش نمی‌کنیم، بلکه از فضای ذخیره‌سازی‌ای استفاده می‌کنیم که مستقل از باز بودن یا نبودن DevTools با مشکلات پر می‌شود. پس‌از باز شدن DevTools (یا، درواقع، متصل شدن هر کارخواه CDP دیگر)، همه مشکلات ثبت‌شده قبلی را می‌توان از فضای ذخیره‌سازی بازپخش کرد.

این کار باطن را به پایان رساند و اکنون باید روی نحوه نمایش مشکل در ظاهر تمرکز می‌کردیم.

مرحله ۵: طراحی نوشتار مشکلات

طراحی متن مشکلات فرایندی است که علاوه‌بر تیم ما، چندین تیم دیگر را نیز درگیر می‌کند، برای مثال، ما اغلب به بینش تیمی که ویژگی را پیاده‌سازی می‌کند (در این مورد تیم CSP) و البته تیم DevRel که نحوه برخورد توسعه‌دهندگان وب با نوع خاصی از مشکل را طراحی می‌کند، تکیه می‌کنیم. نوشتار مشکل معمولاً تا زمانی که تکمیل شود چندبار اصلاح می‌شود.

معمولاً تیم DevTools با پیش‌نویس اولیه‌ای از آنچه تصور می‌کنند شروع می‌کند:


## Header
Content Security Policy: include all sources of your resources in content security policy header to improve the functioning of your site

## General information
Even though some sources are included in the content security policy header, some resources accessed by your site like images, stylesheets or scripts originate from sources not included in content security policy directives.

Usage of content from not included sources is restricted to strengthen the security of your entire site.

## Specific information

### VIOLATED DIRECTIVES
`img-src 'self'`

### BLOCKED URLs
https://imgur.com/JuXCo1p.jpg

## Specific information
https://web.dev/strict-csp/

پس‌از تکرار، به این نتیجه رسیدیم:

ALT_TEXT_HERE

همان‌طور که می‌بینید، مشارکت دادن تیم ویژگی و DevRel باعث می‌شود شرح بسیار واضح‌تر و دقیق‌تر شود!

مشکلات CSP در صفحه‌تان را می‌توانید در برگه اختصاصی برای نقض‌های CSP نیز پیدا کنید.

اشکال‌زدایی مشکلات «انواع مطمئن»

کار کردن با TT در مقیاس بزرگ بدون ابزارهای توسعه‌دهنده مناسب می‌تواند چالش‌برانگیز باشد.

چاپ کنسول بهبودیافته

وقتی با «اشیاء معتمد» کار می‌کنیم، می‌خواهیم حداقل همان مقدار اطلاعاتی را که برای همتای غیرمعتمد نمایش می‌دهیم نشان دهیم. متأسفانه، درحال‌حاضر هنگام نمایش «شیء مطمئن»، هیچ اطلاعاتی درباره شیء پیچیده نمایش داده نمی‌شود.

دلیلش این است که مقداری که در کنسول نمایش داده می‌شود به‌طور پیش‌فرض از فراخوانی .valueOf() در شیء گرفته می‌شود. بااین‌حال، درمورد Trusted Type، مقدار برگردانده‌شده چندان مفید نیست. درعوض، می‌خواهیم چیزی شبیه به آنچه هنگام تماس با .toString() دریافت می‌کنید داشته باشیم. برای دستیابی به این هدف، باید V8 و Blink را اصلاح کنیم تا مدیریت ویژه‌ای برای اشیاء نوع مطمئن معرفی کنیم.

هرچند به‌دلایل تاریخی این رسیدگی سفارشی در V8 انجام می‌شد، چنین رویکردی معایب مهمی دارد. اشیاء زیادی وجود دارند که به نمایش سفارشی نیاز دارند اما نوع آن‌ها در سطح جاوااسکریپت یکسان است. ازآنجایی‌که V8 جاوا اسکریپت خالص است، نمی‌تواند مفاهیمی را که با Web API مطابقت دارند، مانند Trusted Type، تشخیص دهد. به همین دلیل، V8 باید از جاسازکننده خود (Blink) برای تشخیص آن‌ها کمک بخواهد.

بنابراین، انتقال آن بخش از کد به Blink یا هر جاسازکننده دیگری انتخاب منطقی‌ای به‌نظر می‌رسد. جدا از مشکل افشا، مزایای بسیار دیگری وجود دارد:

  • هر جاساز می‌تواند تولید شرح خودش را داشته باشد
  • تولید شرح ازطریق Blink API بسیار آسان‌تر است
  • Blink به تعریف اصلی شیء دسترسی دارد. بنابراین اگر از .toString() برای تولید شرح استفاده کنیم، هیچ خطری وجود ندارد که .toString() دوباره تعریف شود.

توقف درصورت نقض (در حالت فقط گزارش‌دهی)

درحال‌حاضر، تنها راه اشکال‌زدایی نقض‌های TT تنظیم نقاط گسست روی استثناهای JS است. ازآنجایی‌که نقض‌های TT اعمال‌شده باعث ایجاد استثنا می‌شود، این ویژگی می‌تواند تا حدودی مفید باشد. اما در سناریوهای دنیای واقعی، به کنترل دقیق‌تری بر نقض‌های TT نیاز دارید. به‌ویژه، می‌خواهیم فقط درصورت نقض TT (نه سایر استثناها) متوقف شویم، همچنین در حالت فقط گزارش‌دهی متوقف شویم و بین انواع مختلف نقض TT تمایز قائل شویم.

DevTools ازقبل از طیف گسترده‌ای از نقاط توقف پشتیبانی می‌کند، بنابراین معماری آن کاملاً توسعه‌پذیر است. افزودن نوع نقطه توقف جدید مستلزم تغییراتی در پس‌زمینه (Blink)،‏ CDP، و پیش‌زمینه است. باید فرمان CDP جدیدی معرفی کنیم، بیایید آن را setBreakOnTTViolation بنامیم. This command will be used by the frontend to tell the backend on what sort of TT violations it should break. بخش پشتی، به‌ویژه InspectorDOMDebuggerAgent، یک «کاوشگر» onTTViolation() ارائه خواهد کرد که هربار نقض TT رخ دهد فراخوانده می‌شود. سپس، InspectorDOMDebuggerAgent بررسی می‌کند که آیا این نقض باید نقطه توقف را فعال کند یا نه، و اگر چنین باشد، پیامی به فرانت‌اند ارسال می‌کند تا اجرا را موقتاً متوقف کند.

چه کارهایی انجام شده است و چه کارهایی در پیش است؟

از زمانی که مشکلات شرح‌داده‌شده در اینجا معرفی شدند، برگه مشکلات تغییرات زیادی داشته است:

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

بارگیری کانال‌های پیش‌نمایش

بهتر است از Chrome Canary، Dev، یا Beta به‌عنوان مرورگر توسعه پیش‌فرض استفاده کنید. این کانال‌های پیش‌نمایش به شما امکان می‌دهند به جدیدترین ویژگی‌های DevTools دسترسی داشته باشید، میاناهای برنامه‌سازی کاربردی پلاتفرم وب پیشرفته را آزمایش کنید، و به شما کمک می‌کنند مشکلات سایتتان را قبل‌از اینکه کاربران با آن‌ها مواجه شوند پیدا کنید!

تماس با تیم Chrome DevTools

از گزینه‌های زیر برای بحث درباره ویژگی‌های جدید، به‌روزرسانی‌ها، یا هر چیز دیگری که به DevTools مربوط می‌شود استفاده کنید.