CORE · مفاهیم هدر امنیتی

CSP — سیاست امنیت محتوا

Content Security Policy

سیاست امنیت محتوا (CSP) یک لایه‌ی دفاعیِ مرورگری در برابر XSS است، اما نوعِ مبتنی بر فهرست سفیدِ آن امروز شکسته محسوب می‌شود و رویکردِ درست، سیاستِ مبتنی بر nonce و strict-dynamic است.

تیم فنی پی‌هانتر

CSP چیست و چطور کار می‌کند؟

سیاست امنیت محتوا (Content Security Policy) یک هدرِ HTTP است که به مرورگر می‌گوید محتوای صفحه (به‌ویژه اسکریپت‌ها) از چه منابعی مجاز به بارگذاری و اجراست. هدفِ اصلی‌اش کاهشِ اثرِ XSS است: حتی اگر مهاجم بتواند اسکریپتی تزریق کند، CSP می‌تواند جلوی اجرای آن را بگیرد. CSP همچنین با دستورِ frame-ancestors جای X-Frame-Options را برای ضدِکلیک‌ربایی می‌گیرد و با form-action مقصدِ ارسالِ فرم‌ها را محدود می‌کند.

نکته‌ی محوری این است که CSP یک کاهش‌دهنده است، نه رفع؛ و مدلِ سنتیِ آن که بر فهرست سفیدِ دامنه‌ها استوار بود، در عمل شکست خورده است.

چرا فهرست سفید شکسته است

مبنای تجربیِ این ادعا، مقاله‌ی گوگل با عنوان «CSP مرده است، زنده باد CSP» در کنفرانسِ CCS 2016 است. یافته‌های آن مطالعه:

  • ۹۴٫۷۲٪ از سیاست‌های متمایزِ بررسی‌شده دارای راهِ دور زدن بودند.
  • ۷۵٫۸۱٪ از سیاست‌هایی که فهرست سفیدِ اسکریپت داشتند، قابل دور زدن بودند.
  • ۹۹٫۳۴٪ از میزبان‌هایی که CSP مستقر کرده بودند، سیاستی داشتند که هیچ محافظتِ واقعی در برابر XSS نمی‌داد.
  • ۱۴ مورد از ۱۵ دامنه‌ای که بیش از همه در فهرست سفیدِ بارگذاریِ اسکریپت قرار می‌گیرند، دارای اندپوینت‌های ناامن بودند.

دلیلِ ساختاری: هر دامنه‌ی مجازی که یک اندپوینتِ JSONP، یک نسخه‌ی AngularJS، یا یک CDN با سرویسِ مسیرِ دلخواه داشته باشد، به یک گجتِ اجرای اسکریپت بدل می‌شود. نگهداریِ یک فهرست سفید کارِ بی‌پایانی است که مدافع در آن برنده نمی‌شود.

سیاست درست: nonce و strict-dynamic

رویکردِ توصیه‌شده‌ی OWASP، سیاستِ سخت‌گیرانه‌ی مبتنی بر nonce است:

Content-Security-Policy:
  script-src 'nonce-{RANDOM}' 'strict-dynamic';
  object-src 'none';
  base-uri 'none';
  • nonce باید یک مقدارِ تصادفیِ رمزنگارانه و تازه به‌ازای هر پاسخِ HTTP باشد؛ nonceِ ثابت یا قابل‌پیش‌بینی بی‌ارزش است.
  • strict-dynamic اعتماد را از یک اسکریپتِ دارای nonce به اسکریپت‌هایی که آن به‌صورت پویا می‌سازد منتقل می‌کند؛ همین است که سیاستِ سخت را در برنامه‌های دارای loader/bundler بدونِ فهرست سفید قابلِ استقرار می‌کند.
  • object-src 'none' دور زدن‌های مبتنی بر پلاگین را می‌بندد.
  • base-uri 'none' جلوی تزریقِ <base> برای ربودنِ آدرس‌های نسبیِ اسکریپت را می‌گیرد.

هشدارِ OWASP: از میدل‌وری که کورکورانه به هر تگِ اسکریپت nonce می‌چسباند بپرهیزید، چون اسکریپتِ تزریق‌شده‌ی مهاجم هم nonce می‌گیرد. ابزارِ سنجش، CSP Evaluatorِ گوگل است.

CSP آسیب‌پذیری را رفع نمی‌کند

باور غلط رایج

«CSP، XSS را رفع می‌کند.» نه — CSP یک کاهش‌دهنده است، نه رفع. اثرِ XSS را کم می‌کند اما خودِ باگ را از بین نمی‌برد. در گزارش تست نفوذ باید XSS را با شدتِ مستقلِ خودش گزارش کرد، حتی اگر CSP وجود داشته باشد. مهم‌تر: سیاستی که در script-src دارای 'unsafe-inline' باشد، عملاً هیچ محافظتی در برابر XSS نمی‌دهد؛ همین‌طور 'unsafe-eval' برای سینک‌های مبتنی بر eval. همچنین CSP در برابر DOM XSS ای که فقط از اسکریپتِ هم‌مبدأ استفاده می‌کند محافظت نمی‌دهد؛ آنجا Trusted Types با دستورِ require-trusted-types-for 'script' لازم است.

روش استقرار: حالت گزارش‌فقط

استقرارِ CSP بدونِ شکستنِ سایت نیازمندِ روش است. ابتدا سیاست را در حالتِ Content-Security-Policy-Report-Only منتشر کنید؛ در این حالت مرورگر چیزی را مسدود نمی‌کند اما نقض‌ها را گزارش می‌دهد. با report-to/report-uri این گزارش‌ها را جمع کنید، سیاست را بر اساس آن‌ها اصلاح کنید، و تنها پس از اطمینان به حالتِ اجرایی (Content-Security-Policy) سوئیچ کنید. گزارش‌های نقض در کنسولِ مرورگر هم دیده می‌شوند و سریع‌ترین راهِ فهمِ رفتارِ واقعیِ سیاست‌اند.

ارتباط با OWASP و CWE

CSP یک کنترلِ دفاعی است نه یک آسیب‌پذیری؛ اما مستقیماً به XSS مربوط می‌شود که زیر A05:2025 تزریق (CWE-79) قرار دارد. نبودِ هدرهای امنیتی مثل CSP نیز می‌تواند زیر A02:2025 (پیکربندی نادرست) گزارش شود. برای دفاعِ کاملِ XSS، CSP را با کدگذاریِ خروجیِ متناسب با زمینه و Trusted Types ترکیب کنید — نه به‌جای آن‌ها. مطالعه‌ی امنیت برنامه‌ی وب تصویرِ کامل‌تری می‌دهد.

پرسش‌های متداول

آیا CSP جلوی XSS را می‌گیرد؟

CSP اثرِ XSS را کاهش می‌دهد اما آن را رفع نمی‌کند. یک سیاستِ سخت‌گیرانه‌ی مبتنی بر nonce می‌تواند اجرای اسکریپتِ تزریق‌شده را مسدود کند، اما اگر 'unsafe-inline' در سیاست باشد عملاً هیچ محافظتی نمی‌دهد. XSS باید در کد رفع و مستقلاً گزارش شود.

چرا CSP مبتنی بر فهرست سفید توصیه نمی‌شود؟

چون در عمل شکسته است. مطالعه‌ی گوگل در CCS 2016 نشان داد ۹۴٫۷۲٪ سیاست‌ها راهِ دور زدن داشتند و ۱۴ مورد از ۱۵ دامنه‌ی پرکاربردِ فهرست سفید، اندپوینتِ ناامن داشتند. رویکردِ درست، nonce + strict-dynamic است.

CSP را چطور بدون خراب‌کردن سایت مستقر کنم؟

ابتدا با هدرِ Content-Security-Policy-Report-Only؛ در این حالت مرورگر چیزی را مسدود نمی‌کند اما نقض‌ها را گزارش می‌دهد. پس از جمع‌آوری و اصلاح بر اساس گزارش‌ها، به هدرِ اجراییِ Content-Security-Policy سوئیچ کنید.

strict-dynamic چه می‌کند؟

اعتماد را از یک اسکریپتِ دارای nonce به اسکریپت‌هایی که آن به‌صورت پویا بارگذاری می‌کند منتقل می‌کند. همین باعث می‌شود سیاستِ سخت‌گیرانه در برنامه‌های دارای loader و bundler، بدونِ نیاز به فهرست سفیدِ دامنه، قابل استقرار باشد.

پیشگیری / رفع

استقرارِ درستِ CSP:

  • سیاستِ سخت‌گیرانه‌ی مبتنی بر nonce + strict-dynamic + object-src 'none' + base-uri 'none' را به کار ببرید؛ از فهرست سفیدِ دامنه‌ها بپرهیزید.
  • nonce را برای هر پاسخ تازه و تصادفیِ رمزنگارانه تولید کنید.
  • هرگز 'unsafe-inline' یا 'unsafe-eval' را در script-src قرار ندهید؛ حضورشان محافظت را تُهی می‌کند.
  • ابتدا با Content-Security-Policy-Report-Only منتشر کنید، نقض‌ها را جمع و سیاست را اصلاح کنید، سپس به حالت اجرایی بروید.
  • CSP را مکملِ رفعِ واقعیِ XSS بدانید، نه جایگزینِ آن؛ XSS را با شدتِ مستقل گزارش کنید.
  • برای DOM XSS، Trusted Types را با require-trusted-types-for 'script' اضافه کنید.
  • سیاست را با CSP Evaluator گوگل بسنجید.

واژه‌های مرتبط

→ بازگشت به دانشنامه
PUT IT TO THE TEST

امنیت سامانه‌ی شما را
به مهاجمان واگذار نکنید

تیم پی‌هانتر با دیدِ یک مهاجم واقعی، این آسیب‌پذیری‌ها و ده‌ها مورد دیگر را روی دارایی‌های شما می‌سنجد.