مدل امنیتی وب ریشه در سیاست مبدا یکسان دارد. کد از https://mybank.com
فقط باید به داده های https://mybank.com
دسترسی داشته باشد و https://evil.example.com
مطمئناً هرگز نباید اجازه دسترسی داشته باشد. هر منبع از بقیه وب جدا نگه داشته می شود و به توسعه دهندگان یک جعبه ایمنی امن برای ساخت و بازی می دهد. از نظر تئوری، این کاملاً درخشان است. در عمل، مهاجمان راه های هوشمندانه ای برای براندازی سیستم پیدا کرده اند.
به عنوان مثال، حملات اسکریپت بین سایتی (XSS) ، با فریب دادن یک سایت برای ارائه کد مخرب همراه با محتوای مورد نظر، از همان سیاست مبدا دور می زند. این یک مشکل بزرگ است، زیرا مرورگرها به تمام کدهایی که در یک صفحه نشان داده می شوند به عنوان بخشی از منبع امنیتی آن صفحه اعتماد دارند. برگه تقلب XSS یک بخش قدیمی اما نماینده روش هایی است که مهاجم ممکن است برای نقض این اعتماد با تزریق کد مخرب استفاده کند. اگر مهاجم با موفقیت هر کدی را تزریق کند، تقریباً بازی تمام میشود: دادههای جلسه کاربر به خطر میافتد و اطلاعاتی که باید مخفی نگه داشته شوند به The Bad Guys منتقل میشوند. بدیهی است که مایلیم در صورت امکان از آن جلوگیری کنیم.
این نمای کلی دفاعی را برجسته می کند که می تواند به طور قابل توجهی خطر و تأثیر حملات XSS را در مرورگرهای مدرن کاهش دهد: سیاست امنیتی محتوا (CSP).
TL; DR
- از لیست های مجاز استفاده کنید تا به مشتری بگویید چه چیزی مجاز است و چه چیزی مجاز نیست.
- بیاموزید چه دستورالعمل هایی در دسترس است.
- کلمات کلیدی آنها را یاد بگیرید.
- کد درون خطی و
eval()
مضر در نظر گرفته می شوند. - قبل از اعمال موارد نقض خط مشی به سرور خود گزارش دهید.
فهرست های مجاز منبع
مشکلی که توسط حملات XSS مورد سوء استفاده قرار می گیرد، ناتوانی مرورگر در تشخیص تمایز بین اسکریپتی است که بخشی از برنامه شما است و اسکریپتی که به طور مخرب توسط شخص ثالث تزریق شده است. برای مثال، دکمه Google +1 در پایین این صفحه کد را از https://apis.google.com/js/plusone.js
در زمینه مبدا این صفحه بارگیری و اجرا می کند. ما به این کد اعتماد داریم، اما نمیتوانیم انتظار داشته باشیم که مرورگر به تنهایی متوجه شود که کد apis.google.com
عالی است، در حالی که کد apis.evil.example.com
احتمالاً اینطور نیست. مرورگر با خوشحالی هر کدی را که یک صفحه درخواست می کند، بدون توجه به منبع، دانلود و اجرا می کند.
به جای اعتماد کورکورانه به همه چیزهایی که یک سرور ارائه میکند، CSP سربرگ Content-Security-Policy
HTTP را تعریف میکند که به شما امکان میدهد یک لیست مجاز از منابع محتوای قابل اعتماد ایجاد کنید و به مرورگر دستور میدهد که فقط منابع را از آن منابع اجرا یا ارائه کند. حتی اگر مهاجم بتواند سوراخی برای تزریق اسکریپت پیدا کند، اسکریپت با لیست مجاز مطابقت نخواهد داشت و در نتیجه اجرا نمیشود.
از آنجایی که ما به apis.google.com
برای ارائه کد معتبر اعتماد داریم، و به خودمان نیز اعتماد داریم که این کار را انجام میدهیم، بیایید خطمشی را تعریف کنیم که فقط زمانی که اسکریپت از یکی از این دو منبع میآید اجازه اجرای آن را میدهد:
Content-Security-Policy: script-src 'self' https://apis.google.com
ساده است، درست است؟ همانطور که احتمالا حدس زدید، script-src
دستورالعملی است که مجموعه ای از امتیازات مربوط به اسکریپت را برای یک صفحه خاص کنترل می کند. ما 'self'
به عنوان یک منبع معتبر از اسکریپت و https://apis.google.com
به عنوان منبع دیگری مشخص کرده ایم. مرورگر با وظیفهشناسی جاوا اسکریپت را از apis.google.com
از طریق HTTPS و همچنین از مبدا صفحه فعلی دانلود و اجرا میکند.
![خطای کنسول: از بارگیری اسکریپت «http://evil.example.com/evil.js» خودداری کرد زیرا دستورالعمل خطمشی امنیت محتوای زیر را نقض میکند: script-src «self» https://apis.google.com](https://developer.chrome.com/static/docs/privacy-security/csp/image/console-error-refused-l-524026adbb83a.png?authuser=1&hl=fa)
با تعریف این خط مشی، مرورگر به جای بارگیری اسکریپت از هر منبع دیگری، به سادگی خطا می دهد. هنگامی که یک مهاجم باهوش موفق می شود کد را به سایت شما تزریق کند، به جای موفقیتی که انتظارش را داشتند، با پیغام خطا مواجه می شوند.
خط مشی برای طیف گسترده ای از منابع اعمال می شود
در حالی که منابع اسکریپت آشکارترین خطرات امنیتی هستند، CSP مجموعه ای غنی از دستورالعمل های خط مشی را ارائه می دهد که کنترل نسبتاً دقیقی را بر منابعی که یک صفحه مجاز به بارگیری آنها است امکان پذیر می کند. شما قبلاً script-src
را دیدهاید، بنابراین مفهوم باید واضح باشد.
بیایید به سرعت بقیه دستورالعمل های منابع را مرور کنیم. لیست زیر وضعیت دستورالعمل ها را در سطح 2 نشان می دهد. مشخصات سطح 3 منتشر شده است، اما تا حد زیادی در مرورگرهای اصلی اجرا نمی شود.
-
base-uri
URL هایی را که می توانند در عنصر<base>
صفحه ظاهر شوند محدود می کند. -
child-src
نشانیهای اینترنتی کارگران و محتویات قاب تعبیهشده را فهرست میکند. به عنوان مثال:child-src https://youtube.com
جاسازی ویدیوها را از YouTube فعال می کند اما نه از منابع دیگر. -
connect-src
منابعی را که می توانید به آنها متصل شوید (از طریق XHR، WebSockets و EventSource) محدود می کند. -
font-src
مبداهایی را مشخص می کند که می توانند فونت های وب را ارائه دهند. فونت های وب Google را می توان از طریقfont-src https://themes.googleusercontent.com
فعال کرد. -
form-action
نقاط پایانی معتبر را برای ارسال از تگهای<form>
فهرست میکند. -
frame-ancestors
منابعی را مشخص می کند که می توانند صفحه فعلی را جاسازی کنند. این دستورالعمل برای تگ های<frame>
،<iframe>
،<embed>
و<applet>
اعمال می شود. این دستورالعمل نمی تواند در تگ های<meta>
استفاده شود و فقط برای منابع غیر HTML اعمال می شود. -
frame-src
در سطح 2 منسوخ شده است، اما در سطح 3 بازیابی می شود. اگر وجود نداشته باشد همچنان بهchild-src
مانند قبل برمی گردد. -
img-src
مبداهایی را که می توان تصاویر را از آنجا بارگذاری کرد، مشخص می کند. -
media-src
منابع مجاز برای ارائه ویدئو و صدا را محدود می کند. -
object-src
امکان کنترل بر روی Flash و سایر پلاگین ها را فراهم می کند. -
plugin-types
انواع افزونه هایی را که ممکن است یک صفحه استفاده کند محدود می کند. -
report-uri
نشانی اینترنتی را مشخص میکند که در صورت نقض خطمشی امنیت محتوا، مرورگر گزارشهایی را ارسال میکند. این دستورالعمل را نمی توان در تگ های<meta>
استفاده کرد. -
style-src
همتایscript-src
برای stylesheets است. -
upgrade-insecure-requests
به عوامل کاربر دستور میدهد تا طرحهای URL را بازنویسی کنند و HTTP را به HTTPS تغییر دهند. این دستورالعمل برای وب سایت هایی با تعداد زیادی URL قدیمی است که نیاز به بازنویسی دارند. -
worker-src
یک دستورالعمل CSP سطح 3 است که URL هایی را که ممکن است به عنوان کارگر، کارگر مشترک یا سرویس دهنده بارگذاری شوند، محدود می کند. از جولای 2017، اجرای این دستورالعمل محدود است.
به طور پیش فرض، دستورالعمل ها کاملاً باز هستند. اگر خط مشی خاصی را برای یک دستورالعمل تنظیم نکنید، مثلاً font-src
، آن رهنمود به طور پیشفرض طوری رفتار میکند که گویی *
بهعنوان منبع معتبر مشخص کردهاید (به عنوان مثال، میتوانید فونتها را از هر جایی بارگیری کنید، بدون محدودیت) .
شما می توانید این رفتار پیش فرض را با تعیین یک دستورالعمل default-src
لغو کنید. این دستورالعمل، پیشفرضهای بیشتر دستورالعملهایی را که نامشخص میگذارید، تعریف میکند. به طور کلی، این امر در مورد هر دستورالعملی که با -src
ختم می شود صدق می کند. اگر default-src
روی https://example.com
تنظیم شده باشد، و نتوانید دستور font-src
را تعیین کنید، میتوانید فونتها را از https://example.com
بارگیری کنید، و هیچ جای دیگری. ما در مثال های قبلی خود فقط script-src
را مشخص کردیم، به این معنی که تصاویر، فونت ها و غیره را می توان از هر منبعی بارگیری کرد.
دستورالعمل های زیر از default-src
به عنوان بازگشتی استفاده نمی کنند. به یاد داشته باشید که تنظیم نکردن آنها مانند اجازه دادن به هر چیزی است.
-
base-uri
-
form-action
-
frame-ancestors
-
plugin-types
-
report-uri
-
sandbox
شما می توانید به تعداد یا تعداد کمی از این دستورالعمل ها که برای برنامه خاص خود منطقی است استفاده کنید، به سادگی هر کدام را در هدر HTTP فهرست کنید و دستورالعمل ها را با نقطه ویرگول از هم جدا کنید. اطمینان حاصل کنید که تمام منابع مورد نیاز از یک نوع خاص را در یک دستورالعمل واحد فهرست کرده اید. اگر چیزی مانند script-src https://host1.com; script-src https://host2.com
دستور دوم به سادگی نادیده گرفته می شود. چیزی شبیه به زیر به درستی هر دو مبدا معتبر را مشخص می کند:
script-src https://host1.com https://host2.com
برای مثال، اگر برنامهای دارید که تمام منابع خود را از یک شبکه تحویل محتوا بارگیری میکند (مثلاً https://cdn.example.net
)، و میدانید که به هیچ محتوای قاب یا افزونهای نیاز ندارید، پس سیاست ممکن است چیزی شبیه به زیر باشد:
Content-Security-Policy: default-src https://cdn.example.net; child-src 'none'; object-src 'none'
جزئیات پیاده سازی
هدرهای X-WebKit-CSP
و X-Content-Security-Policy
در آموزش های مختلف در وب خواهید دید. در ادامه، باید این هدرهای پیشوندی را نادیده بگیرید. مرورگرهای مدرن (به استثنای IE) از سربرگ Content-Security-Policy
بدون پیشوند پشتیبانی می کنند. این هدری است که باید از آن استفاده کنید.
صرف نظر از هدری که استفاده میکنید، خطمشی بر اساس صفحه به صفحه تعریف میشود: باید سرصفحه HTTP را همراه با هر پاسخی که میخواهید از محافظت آن اطمینان حاصل کنید، ارسال کنید. این انعطاف پذیری زیادی را فراهم می کند، زیرا می توانید خط مشی را برای صفحات خاص بر اساس نیازهای خاص آنها تنظیم کنید. شاید یک مجموعه از صفحات در سایت شما دارای دکمه 1+ باشد، در حالی که سایرین اینگونه نیستند: شما می توانید اجازه دهید کد دکمه فقط در صورت لزوم بارگذاری شود.
فهرست منبع در هر دستورالعمل قابل انعطاف است. میتوانید منابع را بر اساس طرح ( data:
https:
:)، یا از نظر ویژگی از hostname-only ( example.com
، که با هر منبعی در آن میزبان مطابقت دارد: هر طرح، هر پورت) تا یک URI کاملاً واجد شرایط ( https://example.com:443
کنید. https://example.com:443
، که فقط با HTTPS، فقط example.com
و فقط پورت 443 مطابقت دارد. حروف عام پذیرفته می شوند، اما فقط به عنوان یک طرح، یک پورت، یا در سمت چپ ترین موقعیت نام میزبان: *://*.example.com:*
با همه زیر دامنه های example.com
(اما نه خود example.com
) مطابقت دارد. با استفاده از هر طرحی، در هر پورتی.
فهرست منبع نیز چهار کلمه کلیدی را می پذیرد:
-
'none'
، همانطور که ممکن است انتظار داشته باشید، با هیچ چیز مطابقت ندارد. -
'self'
با مبدأ فعلی مطابقت دارد، اما نه با زیر دامنههای آن. -
'unsafe-inline'
به جاوا اسکریپت و CSS درون خطی اجازه می دهد. (در این مورد با جزئیات بیشتری صحبت خواهیم کرد.) -
'unsafe-eval'
به مکانیسم های تبدیل متن به جاوا اسکریپت مانندeval
اجازه می دهد. (به این هم خواهیم رسید.)
این کلمات کلیدی به نقل قول تک نیاز دارند. به عنوان مثال، script-src 'self'
(با نقل قول) اجازه اجرای جاوا اسکریپت را از میزبان فعلی می دهد. script-src self
(بدون نقل قول) جاوا اسکریپت را از سروری به نام " self
" (و نه از میزبان فعلی) اجازه می دهد، که احتمالاً منظور شما این نیست.
سندباکس
یک دستورالعمل دیگر وجود دارد که ارزش صحبت کردن دارد: sandbox
. این کمی متفاوت از سایر مواردی است که ما به آنها نگاه کرده ایم، زیرا محدودیت هایی را برای اقداماتی که صفحه می تواند انجام دهد به جای منابعی که صفحه می تواند بارگذاری کند، ایجاد می کند. اگر دستورالعمل sandbox
وجود داشته باشد، با صفحه به گونهای رفتار میشود که انگار در داخل یک <iframe>
با ویژگی sandbox
بارگذاری شده است. این میتواند طیف گستردهای از اثرات را روی صفحه داشته باشد: وادار کردن صفحه به یک مبدأ منحصر به فرد، و جلوگیری از ارسال فرم، از جمله. این کمی فراتر از محدوده این مقاله است، اما میتوانید جزئیات کامل ویژگیهای sandboxing معتبر را در بخش «Sandboxing» از مشخصات HTML5 بیابید.
متا تگ
مکانیسم تحویل ترجیحی CSP ها یک هدر HTTP است. با این حال، تنظیم یک خط مشی در صفحه مستقیماً در نشانه گذاری می تواند مفید باشد. این کار را با استفاده از تگ <meta>
با ویژگی http-equiv
انجام دهید:
<meta
http-equiv="Content-Security-Policy"
content="default-src https://cdn.example.net; child-src 'none'; object-src 'none'"
/>
این را نمی توان برای frame-ancestors
، report-uri
یا sandbox
استفاده کرد.
کد درون خطی مضر تلقی می شود
باید واضح باشد که CSP بر اساس مبدأهای لیست مجاز است، زیرا این روشی بدون ابهام برای دستور دادن به مرورگر است تا مجموعه خاصی از منابع را قابل قبول در نظر بگیرد و بقیه را رد کند. با این حال، لیست های مجاز مبتنی بر مبدا بزرگترین تهدید ناشی از حملات XSS را حل نمی کنند: تزریق اسکریپت درون خطی. اگر یک مهاجم بتواند یک تگ اسکریپت را تزریق کند که مستقیماً حاوی مقداری بار مخرب است ( <script>sendMyDataToEvilDotCom();</script>
)، مرورگر هیچ مکانیزمی برای تشخیص آن از یک تگ اسکریپت درون خطی قانونی ندارد. CSP این مشکل را با ممنوع کردن کامل اسکریپت درون خطی حل می کند: این تنها راه برای اطمینان است.
این ممنوعیت نه تنها شامل اسکریپتهایی میشود که مستقیماً در برچسبهای script
جاسازی شدهاند، بلکه شامل کنترلکنندههای رویداد درون خطی و javascript:
URLها نیز میشود. شما باید محتوای تگهای script
را به یک فایل خارجی منتقل کنید و javascript:
URLها و <a ... onclick="[JAVASCRIPT]">
را با فراخوانهای مناسب addEventListener()
جایگزین کنید. به عنوان مثال، می توانید موارد زیر را بازنویسی کنید:
<script>
function doAmazingThings() {
alert('YOU AM AMAZING!');
}
</script>
<button onclick="doAmazingThings();">Am I amazing?</button>
به چیزی بیشتر شبیه به:
<!-- amazing.html -->
<script src="amazing.js"></script>
<button id="amazing">Am I amazing?</button>
<div style="clear:both;"></div>
// amazing.js
function doAmazingThings() {
alert('YOU AM AMAZING!');
}
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('amazing').addEventListener('click', doAmazingThings);
});
کد بازنویسی شده دارای چندین مزیت بالا و فراتر از کار خوب با CSP است. بدون توجه به استفاده شما از CSP، در حال حاضر بهترین روش است. جاوا اسکریپت درون خطی ساختار و رفتار را دقیقاً به روشی که نباید ترکیب می کند. ذخیره منابع خارجی برای مرورگرها آسان تر است، برای توسعه دهندگان قابل درک تر است و برای جمع آوری و کوچک سازی مفید است. اگر کار انتقال کد به منابع خارجی را انجام دهید، کد بهتری خواهید نوشت.
با سبک درون خطی نیز به همین صورت رفتار میشود: هم ویژگی style
و هم تگهای style
باید در شیوهنامههای خارجی ادغام شوند تا در برابر انواع روشهای شگفتآور استخراج دادهای که CSS فعال میکند محافظت شود.
اگر باید اسکریپت و استایل درون خطی داشته باشید، میتوانید با افزودن 'unsafe-inline'
به عنوان منبع مجاز در دستورالعمل script-src
یا style-src
آن را فعال کنید. شما همچنین می توانید از nonce یا هش استفاده کنید (به زیر مراجعه کنید)، اما واقعاً نباید این کار را انجام دهید. ممنوع کردن اسکریپت درون خطی بزرگترین پیروزی امنیتی است که CSP ارائه می کند، و ممنوع کردن سبک درون خطی نیز برنامه شما را سخت می کند. برای اطمینان از اینکه کارها پس از جابجایی همه کدهای خارج از خط به درستی کار میکنند، کمی تلاش است، اما این معاملهای است که ارزش انجام آن را دارد.
اگر حتما باید از آن استفاده کنید
CSP Level 2 با استفاده از یک nonce رمزنگاری (تعداد یک بار استفاده شده) یا یک هش، سازگاری رو به عقب را برای اسکریپتهای درون خطی ارائه میدهد. اگرچه این ممکن است دست و پا گیر باشد، اما در یک خرج کردن مفید است.
برای استفاده از nonce، به تگ اسکریپت خود یک ویژگی nonce بدهید. مقدار آن باید با یکی در فهرست منابع قابل اعتماد مطابقت داشته باشد. به عنوان مثال:
<script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">
// Some inline code I can't remove yet, but need to asap.
</script>
حال، nonce را به دستور script-src
خود اضافه کنید که به کلمه کلیدی nonce-
اضافه شده است.
Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'
به یاد داشته باشید که nonces باید برای هر درخواست صفحه دوباره تولید شود و آنها باید غیرقابل حدس زدن باشند.
هش ها تقریباً به همین شکل کار می کنند. به جای اضافه کردن کد به تگ اسکریپت، یک هش SHA از خود اسکریپت ایجاد کنید و آن را به دستور script-src
اضافه کنید. به عنوان مثال، فرض کنید صفحه شما حاوی این است:
<script>
alert('Hello, world.');
</script>
خط مشی شما شامل این موارد می شود:
Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng='
در اینجا چند نکته قابل توجه است. پیشوند sha*-
الگوریتم تولید هش را مشخص می کند. در مثال بالا از sha256-
استفاده شده است. CSP همچنین از sha384-
و sha512-
پشتیبانی می کند. هنگام تولید هش، تگ های <script>
را وارد نکنید. همچنین حروف بزرگ و فضای خالی مهم هستند، از جمله فضای سفید پیشرو یا انتهایی.
جستجوی گوگل در مورد ایجاد هش SHA شما را به راه حل هایی به هر تعداد زبان راهنمایی می کند. با استفاده از Chrome 40 یا جدیدتر، میتوانید DevTools را باز کنید و سپس صفحه خود را بارگیری مجدد کنید. تب Console حاوی پیام های خطا با هش صحیح sha256 برای هر یک از اسکریپت های درون خطی شما خواهد بود.
اوال هم
حتی زمانی که یک مهاجم نمی تواند مستقیماً اسکریپت را تزریق کند، ممکن است بتواند برنامه شما را فریب دهد تا متن غیرفعال را به جاوا اسکریپت اجرایی تبدیل کند و آن را از طرف خود اجرا کند. eval()
، new Function() ، setTimeout([string], ...)
و setInterval([string], ...)
همگی بردارهایی هستند که متن تزریق شده از طریق آنها ممکن است در نهایت چیزی به طور غیرمنتظره ای مخرب را اجرا کند. پاسخ پیشفرض CSP به این خطر، مسدود کردن کامل همه این بردارها است.
این بیش از چند تأثیر بر نحوه ساخت برنامه های کاربردی دارد:
- شما باید JSON را از طریق
JSON.parse
داخلی تجزیه و تحلیل کنید، نه اینکه بهeval
تکیه کنید. عملیات JSON بومی از زمان IE8 در هر مرورگر موجود است و کاملاً ایمن هستند. - هر تماس
setTimeout
یاsetInterval
را که در حال حاضر با توابع درون خطی به جای رشته ها انجام می دهید، بازنویسی کنید. به عنوان مثال:
setTimeout("document.querySelector('a').style.display = 'none';", 10);
بهتر است به صورت زیر نوشته شود:
setTimeout(function () {
document.querySelector('a').style.display = 'none';
}, 10);
- اجتناب از قالب درونی در زمان اجرا: بسیاری از کتابخانه های قالب از
new Function()
به صورت آزادانه برای سرعت بخشیدن به تولید قالب در زمان اجرا استفاده می کنند. این یک برنامه کاربردی عالی از برنامه نویسی پویا است، اما خطر ارزیابی متن مخرب را به همراه دارد. برخی از فریمورکها از CSP خارج از جعبه پشتیبانی میکنند و در غیابeval
به تجزیهکننده قوی بازمیگردند. دستورالعمل ng-csp AngularJS مثال خوبی برای این موضوع است.
با این حال، یک انتخاب بهتر یک زبان قالب است که پیش کامپایل را ارائه می دهد (مثلاً Handlebars این کار را انجام می دهد ). پیشکامپایل کردن قالبهای شما میتواند تجربه کاربر را حتی سریعتر از اجرای سریعترین زمان اجرا کند، و همچنین ایمنتر است. اگر eval و برادران متن به جاوا اسکریپت آن برای برنامه شما ضروری هستند، میتوانید با افزودن 'unsafe-eval'
بهعنوان منبع مجاز در دستورالعمل script-src
، آنها را فعال کنید، اما ما به شدت از این کار جلوگیری میکنیم. ممنوع کردن امکان اجرای رشته ها، اجرای کدهای غیرمجاز در سایت شما را برای مهاجمان بسیار دشوارتر می کند.
گزارش دهی
توانایی CSP برای مسدود کردن منابع نامعتبر سمت مشتری یک پیروزی بزرگ برای کاربران شماست، اما ارسال نوعی اعلان به سرور بسیار مفید خواهد بود تا بتوانید هر گونه اشکالی را که در ابتدا اجازه تزریق مخرب را می دهد شناسایی و برطرف کنید. محل برای این منظور، میتوانید به مرورگر دستور دهید تا گزارشهای نقض با قالب JSON را به مکانی مشخص شده در دستورالعمل report-uri
POST
.
Content-Security-Policy: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;
این گزارش ها چیزی شبیه به زیر خواهند بود:
{
"csp-report": {
"document-uri": "http://example.org/page.html",
"referrer": "http://evil.example.com/",
"blocked-uri": "http://evil.example.com/evil.js",
"violated-directive": "script-src 'self' https://apis.google.com",
"original-policy": "script-src 'self' https://apis.google.com; report-uri http://example.org/my_amazing_csp_report_parser"
}
}
این شامل بخش خوبی از اطلاعات است که به شما کمک می کند علت خاص نقض را ردیابی کنید، از جمله صفحه ای که در آن نقض رخ داده است ( document-uri
)، ارجاع دهنده آن صفحه (توجه داشته باشید که برخلاف فیلد هدر HTTP، کلید این نیست. غلط املایی)، منبعی که خطمشی صفحه را نقض میکند ( blocked-uri
)، دستورالعمل خاصی که آن را نقض کرده است ( violated-directive
)، و خطمشی کامل صفحه ( original-policy
).
فقط گزارش
اگر به تازگی با CSP شروع کرده اید، منطقی است که وضعیت فعلی برنامه خود را قبل از ارائه یک سیاست سختگیرانه برای کاربران خود ارزیابی کنید. بهعنوان پلهای برای استقرار کامل، میتوانید از مرورگر بخواهید که یک خطمشی را نظارت کند، تخلفات را گزارش کند اما محدودیتها را اجرا نکند. به جای ارسال هدر Content-Security-Policy
، یک هدر Content-Security-Policy-Report-Only
ارسال کنید.
Content-Security-Policy-Report-Only: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;
خطمشی مشخصشده در حالت فقط گزارش، منابع محدود را مسدود نمیکند، اما گزارشهای تخلف را به مکانی که شما مشخص کردهاید ارسال میکند. شما حتی می توانید هر دو سرصفحه را ارسال کنید و یک خط مشی را اجرا کنید در حالی که دیگری را نظارت کنید. این یک راه عالی برای ارزیابی تأثیر تغییرات در CSP برنامه شما است: گزارش را برای یک خط مشی جدید روشن کنید، گزارش های نقض را نظارت کنید و هر گونه اشکالی را که ظاهر می شود برطرف کنید. وقتی از تاثیر آن راضی شدید، اجرای سیاست جدید را شروع کنید.
استفاده در دنیای واقعی
CSP 1 کاملاً در کروم، سافاری و فایرفاکس قابل استفاده است، اما پشتیبانی بسیار محدودی در IE 10 دارد. میتوانید مشخصات را در caniuse.com مشاهده کنید . CSP Level 2 از نسخه 40 در کروم در دسترس بوده است. سایتهای عظیمی مانند توییتر و فیسبوک از سربرگ استفاده کردهاند ( مطالعه موردی توییتر ارزش خواندن دارد)، و استاندارد بسیار آماده است تا شما شروع به استقرار در سایتهای خود کنید.
اولین قدم برای ایجاد یک خط مشی برای برنامه شما، ارزیابی منابعی است که در واقع بارگذاری می کنید. هنگامی که فکر می کنید کنترلی در مورد نحوه چیدمان موارد در برنامه خود دارید، سیاستی را بر اساس آن الزامات تنظیم کنید. بیایید چند مورد استفاده رایج را مرور کنیم و تعیین کنیم که چگونه میتوانیم از آنها در محدودههای حفاظتی CSP پشتیبانی کنیم.
مورد استفاده شماره 1: ویجت های رسانه های اجتماعی
دکمه 1+ Google شامل یک اسکریپت از
https://apis.google.com
و یک<iframe>
ازhttps://plusone.google.com
است. برای جاسازی دکمه، به سیاستی نیاز دارید که شامل هر دو مبدا باشد. یک سیاست حداقلیscript-src https://apis.google.com; child-src https://plusone.google.com
. همچنین باید اطمینان حاصل کنید که قطعه جاوا اسکریپتی که Google ارائه می دهد در یک فایل جاوا اسکریپت خارجی بیرون کشیده شده است. اگر خطمشی مبتنی بر سطح 1 با استفاده ازframe-src
سطح 2 داشتید، باید آن را بهchild-src
تغییر دهید. این دیگر در CSP Level 3 ضروری نیست.دکمه لایک فیس بوک دارای تعدادی گزینه اجرایی است. توصیه می کنیم از نسخه
<iframe>
استفاده کنید زیرا به طور ایمن از سایر قسمت های سایت شما ذخیره شده است. برای اینکه به درستی کار کند، به دستورchild-src https://facebook.com
نیاز دارد. توجه داشته باشید که بهطور پیشفرض، کد<iframe>
که فیسبوک ارائه میدهد یک URL نسبی،//facebook.com
را بارگیری میکند. آن را تغییر دهید تا به صراحت HTTPS را مشخص کنید:https://facebook.com
. اگر مجبور نیستید دلیلی برای استفاده از HTTP وجود ندارد.دکمه توییت توییتر متکی به دسترسی به یک اسکریپت و یک فریم است که هر دو در
https://platform.twitter.com
میزبانی می شوند. (تویتر نیز به طور پیشفرض یک URL نسبی ارائه میکند؛ کد را ویرایش کنید تا هنگام کپی/پیست کردن محلی، HTTPS مشخص شود.) باscript-src https://platform.twitter.com; child-src https://platform.twitter.com
، تا زمانی که قطعه جاوا اسکریپتی را که توییتر ارائه می دهد را به یک فایل جاوا اسکریپت خارجی منتقل کنید.سایر پلتفرمها نیازمندیهای مشابهی دارند و میتوان آنها را به طور مشابه مورد بررسی قرار داد. پیشنهاد میکنیم فقط یک
default-src
از'none'
را تنظیم کنید و کنسول خود را تماشا کنید تا مشخص کنید که برای فعال کردن ویجتها باید کدام منابع را فعال کنید.
گنجاندن چندین ویجت ساده است: به سادگی دستورالعمل های خط مشی را ترکیب کنید، به یاد داشته باشید که همه منابع از یک نوع واحد را در یک دستورالعمل واحد ادغام کنید. اگر هر سه ویجت رسانه های اجتماعی را می خواستید، خط مشی به این صورت خواهد بود:
script-src https://apis.google.com https://platform.twitter.com; child-src https://plusone.google.com https://facebook.com https://platform.twitter.com
مورد استفاده شماره 2: قفل کردن
یک لحظه فرض کنید که یک سایت بانکی را راه اندازی می کنید و می خواهید مطمئن شوید که فقط آن منابعی که خودتان نوشته اید قابل بارگیری هستند. در این سناریو، با یک سیاست پیشفرض شروع کنید که مطلقاً همه چیز را مسدود میکند ( default-src 'none'
) و از آنجا ایجاد کنید.
فرض کنید بانک همه تصاویر، سبک و اسکریپت را از یک CDN در https://cdn.mybank.net
بارگیری می کند و از طریق XHR به https://api.mybank.com/
متصل می شود تا بیت های مختلف داده را پایین بکشد. فریم ها استفاده می شوند، اما فقط برای صفحات محلی سایت (بدون منبع شخص ثالث). هیچ فلش در سایت وجود ندارد، هیچ فونت و هیچ چیز اضافی وجود ندارد. محدودترین هدر CSP که می توانیم ارسال کنیم این است:
Content-Security-Policy: default-src 'none'; script-src https://cdn.mybank.net; style-src https://cdn.mybank.net; img-src https://cdn.mybank.net; connect-src https://api.mybank.com; child-src 'self'
استفاده از مورد شماره 3: فقط SSL
یک مدیر انجمن گفتگوی حلقه ازدواج میخواهد اطمینان حاصل کند که همه منابع فقط از طریق کانالهای امن بارگیری میشوند، اما واقعاً کد زیادی نمینویسد. بازنویسی تکه های بزرگ نرم افزار انجمن شخص ثالث که تا لبه با اسکریپت و سبک درون خطی پر شده است فراتر از توانایی های او است. سیاست زیر موثر خواهد بود:
Content-Security-Policy: default-src https:; script-src https: 'unsafe-inline'; style-src https: 'unsafe-inline'
حتی اگر https:
در default-src
مشخص شده است، دستورالعمل های اسکریپت و سبک به طور خودکار آن منبع را به ارث نمی برند. هر دستورالعمل به طور کامل پیشفرض آن نوع خاص از منبع را بازنویسی میکند.
آینده
خط مشی امنیت محتوا سطح 2 یک توصیه نامزد است. کارگروه امنیت برنامه های کاربردی وب W3C قبلاً کار بر روی تکرار بعدی مشخصات، سیاست امنیت محتوا سطح 3 را آغاز کرده است.
اگر به بحث پیرامون این ویژگیهای آینده علاقه دارید، بایگانیهای فهرست پستی public-webappsec@ را مرور کنید یا به خودتان بپیوندید.