امنیت سایت با استفاده از CSP در ASP.Net MVC

در این مقاله قصد داریم بگوییم CSP چیست ، چگونه کار میکند، کجا استفاده می شود، دستورات آن چگونه است و ... . Content Security Policy یا CSP یک HTTP header جدید بزرگ است که کنترل میکند کجا یک مرورگر اجازه بارگذاری محتوا و چه نوع از محتوایی اجازه بارگذاری دارد.

امنیت سایت با استفاده از CSP  در ASP.Net MVC

در این مقاله قصد داریم بگوییم CSP چیست، چگونه کار میکند، کجا استفاده می شود، دستورات آن چگونه است و... .

Content Security Policy یا  CSP یک  HTTP headerجدید بزرگ است که کنترل میکند کجا یک مرورگر اجازه بارگذاری محتوا و چه نوع از محتوایی اجازه بارگذاری دارد. از یک white-list  برای تشخیص مجوز بارگذاری محتواها استفاده میکند، هر محتوایی که در این لیست نباشد اجازه بارگذاری ندارد. یک کنترل دقیق بسیار خوب به ما می دهد و اجازه می دهد تا سایت خود را در sandbox مرورگر کاربران اجرا کنیم.

CSP همه چیز در مورد اضافه کردن یک لایه اضافی امنیتی به سایت شما با استفاده از استراتژی Defence in Depth  است. به شناسایی و کاهش Cross Site Scripting و حملات تزریق داده های مختلف (various  data injection attacks) مانند SQL injection کمک میکند.

در زیر یک نمونه از CSP HTTP header در کروم نشان داده شده است. شکل زیر یک نمونه پروژه MVC  است که CSP  درآن اعمال شده است. در اینجا از ASP.NET MVC Boilerplate  برای ایجاد یک پروژه استفاده شده است که CSP در آن بکاربرده شده است.

 

قسمت آبی شده HTTP header  را نشان می دهد. اساسا درباره مسدود کردن همه چیز بجز اسکریپتها، تصاویر، فونتها،درخواست های Ajax به فرم یا از فرم دامنه ی ما صحبت میکند و به اسکریپتهای مایکروسافت CDN و گوگل اجازه دسترسی می دهد.

 

برای مثال می خواهید فقط CSS  ها ، JavaScript  ها و تصاویر از دامنه بارگذاری شوند و بقیه چیزها مسدود شوند. همچنین اگر بخواهید پلاگین ها (Flash, Silverlight) یا فریم ها را مسدود کنید. با استفاده از این نوع سیاست امنیتی تنها راهی که یک مهاجم می تواند به سایت شما آسیب برساند استفاده از حمله XSS است،  مهاجم می تواند به نحوی یک اسکریپت از دامنه را روی صفحات شما در فایل های اسکریپت جداگانه به صورت استایل های درون خط قرار دهد و به صورت پیش فرض توسط CSP  مسدود نخواهد شد.

با CSP HTTP header  بالا در محل اگر یک مهاجم موفق به تزریق اسکریپت شود، مرورگر خطاهای نقض CSP ارسال میکند و اسکریپتهای مخرب نمی توانند اجرا و حتی دانلود شوند. در زیر می توانید ببینید که در کروم چگونه دیده می شوند.

حتی بهتر آنکه، مرورگر هرگز در وهله اول اسکریپتهای مخرب را دانلود نمیکند. در پایین می توانید دو نمونه از Fiddler را با هم مقایسه کنید. سمت چپ نشان می دهد که فایل Script.js مخرب هرگز درخواست نشده بود اما  یک نقض CSP به URL که نشان داده شده وارد شده است. در سمت راست سایتی بدون تاثیر از CSP را نشان می دهد . مرورگر سعی در دانلود اسکریپت مخرب دارد ، این یک نسخه نمایشی است به همین دلیل خطای 404 رخ می دهد.

دستورات CSP

تعدادی از دستورات برای استفاده در CPS وجود دارند.در اینجا Mozilla یک لیست کامل از دستورات و چگونگی استفاده از آنها دارد. هر کنترل دستور دسترسی به یک تابع خاص در مرورگر دارد. مهم ترین آنها را بررسی خواهیم کرد.

 دستور  default-src

دستور default-src به ما اجازه می دهد محدودیت هایی را به کار ببریم. برای مثال دستور CSP زیر روی انواع محتواهای دامنه سایت ما و همچنین TrustedSite.com  تاثیر گذار است.

در حال حاضر Policy  بالا بسیار سست است، به مرورگر اجازه بارگذاری Frame ها ، Ajax ، Web Socket  ها ،فونت ها ، عکس ها ، صدا ها ، ویدیو ها ،درخواست ها ، Plugin  ها ، Style  ها و اسکریپتها را می دهد. ممکن است از بسیاری از گزینه های موجود در آن لیست استفاده نکنید. یک Policy  بهتر همه چیز را به صورت پیش فرض مسدود میکند و فقط به منابع مطمئن که استفاده کردیده اید به صورت زیر اجازه دسترسی می دهد.

 

می توانید ببینید که default-src  به None فرستاده شده است که به صورت پیش فرض همه چیز را مسدود میکند. سپس دستورات دیگری را اضافه کردیم که به اسکریپتهای TrustedSite.com و سبکها، عکسها، فونت ها، درخواست های Ajax  و فرم های ارسالی به دامنه سایت ما اجازه بارگذاری می دهد. این روش امنیت و محدودیت بیشتری دارد اما نیاز است که درباره Policy  سایت خود بیشتر فکر کنید.

دستور report-uri

 دستور report-uri یک دستورالعمل خاص دیگر است. به مرورگر یک URL می دهد که جزئیات هر نقضی را با فرمت Json  به یک  CSP policyبفرستد. اهمیت زیادی دارد و به ما اجازه می دهد تا هرکس تلاش برای هک کردن سایت ما کرد متوجه شویم، به ما اجازه می دهد تا منابعی که به اشتباه مسدود شده اند را پیدا کنیم زیرا Policy  ما بسیار محدود بوده و به اندازه کافی تست انجام ندادیم. در مثال زیر به مرورگر میگوییم خطای نقض CSP را با فرمت Json  به WebResource.axd?cspReport=true بفرستد.

اگر در بالا اسکریپت مخرب بگیریم و با استفاده از CSP Policy  آن را به صفحه خود اضافه کنیم، یک خطای نقض CSP رخ خواهد داد و Json  بوسیله کروم به ما فرستاده می شود. توجه داشته باشید که مرورگرهای مختلف ، خطاها را با کمی تفاوت ارسال میکنند. بعضی مرورگرها و درواقع ورژنی از مرورگرها اطلاعات بیشتری نسبت به بقیه می دهند.

دستور style-src

همانطور که گفته شد سبک های درون خطی یا  in-line styles زمانی که از CSP استفاده می شود اجازه استفاده ندارند زیرا باعث بروز ریسک برای حمله یک مهاجم که می تواند به یک صفحه در معرض خطر in-line style  تزریق کند می شود. همه استایل ها باید از یک فایل CSS  خارجی استفاده کنند.

یک راه توسعه برای این دستور است که استفاده از استایل های درون خط را مجاز میکند اما باید از آن پرهیز کرد زیرا نا امن است . در واقع در تنظیماتی که برای استایل قرار دادید دستور unsafe-inline  را قرار می دهید.

دستور Script-src

همانند دستور style-src  است ، باعث می شود به طور پیش فرض اسکریپتهای درون خطی ناشی از حملات XSS مسدود شوند. به غیر از اسکریپتهای درون خطی، تابع جاوا اسکریپت eval() نیز به صورت پیش فرض مسدود می شود.

مانند دستور style-src  در اینجا هم یک راه برای فعال کردن اسکریپت درون خط که unsafe-inline نامیده می شود. اینجا یک دستور دیگر نیز با نام unsafe-eval وجود دارد که اجازه دسترسی به تابع eval  را می دهد. یکبار دیگر تذکر داده می شود که باید از unsafe ها اجتناب کرد و در اینجا فقط برای آشنایی شما گفته شده است.

اگر تنظیمات بدی برای CSP قرار دهید می تواند بسیار خطرناک باشد. فرض کنید یک کاربر به سایت شما وارد می شود و میخواهد یک ویدیو youtube  را از روی سایت شما تماشا کند و CSP  ویدیو را مسدود کرده و کاربران فقط یک صفحه خالی میبینند ، مگر اینکه به اندازه کافی باهوش باشند و از ابزارهای مرورگر استفاده کنند. برای مبارزه با این مشکل ، W3C یک Content-Security-Policy-Report-Only HTTP header   ایجاد کرده است. این ابزار همانند CSP است اما تنها از نقض های policy گزارش می دهد و موجب مسدود شدن هر چیزی در مرورگر نمی شود.

CSP برای  ASP.NET MVC

چگونه می توان CSP  را بر روی ASP.Net MVC  پیاده سازی کرد. برای شروع نیاز دارید NWebsec.Mvc را در NuGet pakage  نصب کنید.

NWebsec.Mvc یک مجموعه بزرگ از فیلترهای MVC  است که می تواند به صورت سراسری در همه درخواست ها یا کنترلر ها یا اکشن ها(Actions) بکاربرده شود. NWebsec شامل یک سری از فیلترهای MVC می شود که از CSP پشتیبانی میکند.

در تصویر زیر CSP  در ASP.NetMVC Boilerplate بکاربرده شده و کدهای استفاده شده برای ایجاد آن نمایش داده شده است. این Policy  در تمام پاسخ های سایت بکاربرده شده است.

// Content-Security-Policy - Add the Content-Security-Policy HTTP header to enable Content-Security-Policy.
GlobalFilters.Filters.Add(new CspAttribute());
// OR
// Content-Security-Policy-Report-Only - Add the Content-Security-Policy-Report-Only HTTP header to enable logging of 
//      violations without blocking them. This is good for testing CSP without enabling it.
//      To make use of this attribute, rename all the attributes below to their ReportOnlyAttribute versions e.g. CspDefaultSrcAttribute 
//      becomes CspDefaultSrcReportOnlyAttribute.
// GlobalFilters.Filters.Add(new CspReportOnlyAttribute());
 
// default-src - Sets a default source list for a number of directives. If the other directives below are not used 
//               then this is the default setting.
filters.Add(
    new CspDefaultSrcAttribute()
    {
        // Disallow everything from the same domain by default.
        None = true,
        // Allow everything from the same domain by default.
        // Self = true
    });
 
// connect-src - This directive restricts which URIs the protected resource can load using script interfaces 
//               (Ajax Calls and Web Sockets).
filters.Add(
    new CspConnectSrcAttribute()
    {
        // Allow AJAX and Web Sockets to example.com.
        // CustomSources = "example.com",
        // Allow all AJAX and Web Sockets calls from the same domain.
        Self = true
    });
// font-src - This directive restricts from where the protected resource can load fonts.
filters.Add(
    new CspFontSrcAttribute()
    {
        // Allow fonts from example.com.
        // CustomSources = "example.com",
        // Allow all fonts from the same domain.
        Self = true
    });
// form-action - This directive restricts which URLs can be used as the action of HTML form elements.
filters.Add(
    new CspFormActionAttribute()
    {
        // Allow forms to post back to example.com.
        // CustomSources = "example.com",
        // Allow forms to post back to the same domain.
        Self = true
    });
// img-src - This directive restricts from where the protected resource can load images.
filters.Add(
    new CspImgSrcAttribute()
    {
        // Allow images from example.com.
        // CustomSources = "example.com",
        // Allow images from the same domain.
        Self = true,
    });
// script-src - This directive restricts which scripts the protected resource can execute. 
//              The directive also controls other resources, such as XSLT style sheets, which can cause the user agent to execute script.
filters.Add(
    new CspScriptSrcAttribute()
    {
        // Allow scripts from the CDN's.
        CustomSources = string.Format("ajax.googleapis.com ajax.aspnetcdn.com"),
        // Allow scripts from the same domain.
        Self = true,
        // Allow the use of the eval() method to create code from strings. This is unsafe and can open your site up to XSS vulnerabilities.
        // UnsafeEval = true,
        // Allow inline JavaScript, this is unsafe and can open your site up to XSS vulnerabilities.
        // UnsafeInline = true
    });
// style-src - This directive restricts which styles the user applies to the protected resource.
filters.Add(
    new CspStyleSrcAttribute()
    {
        // Allow CSS from example.com
        // CustomSources = "example.com",
        // Allow CSS from the same domain.
        Self = true,
        // Allow inline CSS, this is unsafe and can open your site up to XSS vulnerabilities.
        // Note: This is currently enable because Modernizr does not support CSP and includes inline styles
        // in its JavaScript files. This is a security hold. If you don't want to use Modernizr, 
        // be sure to disable unsafe inline styles. For more information see:
        // http://stackoverflow.com/questions/26532234/modernizr-causes-content-security-policy-csp-violation-errors
        // https://github.com/Modernizr/Modernizr/pull/1263
        UnsafeInline = true
    });

توجه کنید که چگونه یک فیلتر MVC  برای هر دستور CSP است. این واقعیت را باید در نظر گرفت که ممکن است بخواهید Action  در یک کنترلر خاص توانایی نمایش ویدیوهای youtube  را داشته باشد، توجه داشته باشید که youtube از iframe ها برای قرار دادن ویدیو ها استفاده میکند و mark-up را به صورت زیر قرار می دهد.

با استفاده از CSP policy  بالا ، مرورگر کروم با خطای زیر مواجه می شود.

لازم است تا دستورات frame-src  و  child-srcرا اضافه کنیم تا بتوان در یک کنترلر خاص استفاده کرد. توجه داشته باشید که child-src  یک دستور CSP 2.0  است و frame-src در CSP 2.0 منسوخ شد اما هنوز از آن  برای مرورگرهای قدیمی استفاده میکنیم .

 

گرچه اگر بخواهیم به یک ویدیوی youtube  برای یک Action نسبت به همه اکشن هادر یک کنترلر اجازه دهیم ، به سادگی صفتی را برای آن اکشن بجای کنترلر قرار می دهیم .

تنظیم کردن گزارش های نقض CSP  کمی پیچیده است. لازم است تا فیلتر CspReportUriAttribute  اضافه شود و یک تابع خاص در فایل Global.asax.cs برای رسیدگی به نقض اضافه شود که به صورت زیر نشان داده شده است.

CspViolationReport یک نماینده Json CSP Violation  است که مرورگر برای شما ارسال میکند. شامل خاصیتهای متعددی می شود که درباره URL  مسدود شده توضیح می دهد (دستور نقض ، عامل کاربری و ... ) .

پشتیبانی مرورگر

FireFox 23+ ، Chorme 25+ ،  Safari 7+ مرورگرهای  و Opera 15+  و ورژن بعدی IE از CSP HTTP header پشتیبانی میکنند.

تعدادی از مرورگرهای قدیمی از CSP با استفاده از X-Content-Security-Policy  یا X-Webkit-CSP  پشتیبانی می کردند اما این پیاده سازی های قدیمی مشکلاتی داشتند و نباید استفاده می شدند.

Content Security Policy (CSP) 2.0

یک Editors Draft در CSP 2.0 به وسیله استاندارهای  W3C نوشته شد.  هدف این ورژن پر کردن شکاف ها و اضافه کردن دستورات جدید برای کنترل کاربران وب ، فریم های جاسازی شده ، برنامه های کاربردی آشکار ، سندهای HTML  بر پایه URL  ، جایی که فرم ها ارسال می شوند و انواعی از پلاگین های مرورگر می توانند بارگذاری شوند. NWebsec از بیشتر این دستورات جدید پشتیبانی میکند.

CSP 1.0  دستورات unsafe-inline داشت که اجازه می داد از  Style  های درون خط و برچسب های اسکریپت استفاده شود اما بسیار خطرناک بود و CSP  را تا اندازه ای بی معنی می کرد. این موضوع به مهاجمان توانایی می داد تا کدهایی را به سایت شما تزریق کنند و به سمت حمله های XSS کشیده شوند. استفاده از CSP 1.0 به معنای بارگذاری  styleها و اسکریپتها از فایل های CSS وjavaScript  جداگانه بود. CSP 2.0  دو راه جدید برای استفاده از in-line style  ها و اسکریپتها معرفی کرد.

Nonces

Nonces کمی شبیه به Anti-forgery Token در ASP.net MVC کار میکند. یک رشته تصادفی رمزنگاری است که به سمت کلاینت در CSP HTTP header تولید و ارسال می شود و همچنین در HTML به همراهStyle  یا برچسب اسکریپت مانند :

مرورگر فقط CSP 1.0  را پشتیبانی میکند و دستورات Nonce را نمی فهمد و اسکریپتهای درون خطی را مسدود خواهد کرد. برای حل این مسئله nonce را با دستورات unsafe-inline  ترکیب کردیم .مرورگر  CSP 1.0 اسکریپتهای درون خطی را مانند قبل اجرا میکند اما مرورگر CSP 2.0  دستورات unsafe-inline  را نادیده می گیرد تا زمانی که nonce  را مشاهده کند و فقط اسکریپتهای درون خطی را با استفاده از تنظیمات  nonce  اجرا میکند. یک مسیر ارتقاء در اختیار سایتهای موجود قرار می دهد که بتوانند از CSP 2.0  بدون نیاز به بازنویسی های انبوه برای خلاص شدن از in-line style ها و اسکریپتها بهره مند شوند.

Nonces  به راحتی می توانند با استفاده از HTML helper اجرا شوند .

 

بزرگترین ضرر این روش آن است که Nonce برای هر پاسخ به سمت کلاینت، متفاوت است. به این معناست که هیچ صفحه ای را با استفاده از Nonce  نمی توان cache  کرد. اگر برای هر کاربر صفحه منحصر به فردی در نظر داشته باشید این مسئله مهمی نخواهد بود ، در غیر این صورت استفاده از nonce  غیرممکن است.

Hashes

استفاده از Hashes راه حلی برای cache  کردن در nonce  است. سرور، Hash را به عنوان سبک خاص(style) یا محتوای برچسب اسکریپت (script tage contents) به حساب می آورد:

دیگر پشتیبانی های CSP

تا اینجا دریافتیم که استفاده از in-line style  ها و اسکریپتها راه درستی نیست. CSP  آنها را مسدود میکند ، همچنین نمی توانید با استفاده از ASP.net MVC  آنها را کوچک و نامفهوم کنید. پس حرکت دادن اسکریپتها به فایل CSS  و Java خارجی می تواند به این معنا باشد که می توانید از CSP  استفاده کنید. CSP در حال حاضر درچند کتابخانه بزرگ پشتیبانی نمی شود.

پشتیبانی  Modernizrبرای CSP

 Modernizr  دراستایل های in-line برای تست قابلیت های مرورگر وب استفاده  می شود و به دستورات in-inline ناامن نیاز است. کتابخانه  AngularJS یک CSP compatible mode  دارد که از یک فایل Css  خارجی استفاده می کند که خیلی ساده تنظیم می شود. جایگزین دیگر ، NWebSec  است که  از Hashes پشتیبانی میکند ، ما می توانیم کار کردن Hashes  را از هر اسکریپتی که از Modernizr استفاده میکند و شامل آن می شود را در داخل  CSP HTTP header  اضافه کنیم.

پشتیبانی لینک جستجو برای CSP

Browser Link یکی از خصوصیت های جالب Visual Studio  است که اجازه به روزرسانی یک View  در MVC هنگام اشکال زدایی را می دهد به همراه یک دکمه  refresh  که هر مرورگری که از آن صفحه استفاده میکرده به روزرسانی شود. متاسفانه این خصوصیت دستی با CSP  سازگار نیست زیرا Visual Studio  یک اسکریپت  in-line به دکمه همان صفحه ای که در حال اشکال زدایی بود اضافه میکند. البته این باعث بروز خطای نقض (CSP Violation Errors) می شود.

اتخاذ جریان CSP

تاکنون وب سایتهای زیادی از CSP استفاده نکرده اند. می تواند دلایل زیر را داشته باشد (تا کنون):

1. عدم پشتیبانی مرورگر

2. عدم اطلاع توسعه دهندگان

3. توسعه دهندگان Framework مانند مایکروسافت و ASP.net MVC  به توسعه دهندگان وب راهی برای پیاده سازی CSP نداده اند. (NWebSec برای پر کردن این شکاف ایجاد شد)

4. رواج استفاده از استایل های درون خط و اسکریپتها و عدم تمایل به سوئیچ کردن به فایل های جداگانه

5. عدم پشتیبانی کتابخانه های عمومی CSS/Javascript  ازCSP  

CSP .6 ، لایه های بیشتری از امنیت با استفاده از استراتژی <a href=”http://en.wikipedia.org/wiki/Defense_in_depth_%28computing%29″>Defence in Depth</a> می دهد. بعضی از توسعه دهندگان وب تا زمانی که هک نشوند به حد کافی امنیت را جدی نمیگیرند. 

7. ورژن قبلی CSP  اشکالات زیادی داشت.(X-Content-Security-Policy   یا X-Webkit-CSP )

8. توسعه دهندگان استفاده مناسب از توانایی گزارش نقض به CSP  را با استفاده از دستورات report-uri ایجاد نکرده اند. اگر یک تخلف پیدا شود می توانید به سرعت بفهمید که کسی در حال حمله به سایت شماست و CSP شما معتبر نیست یا اشکالاتی در سایت شما وجود دارد.

9. توسعه دهندگان وب از تفکیک سایت خود می ترسند. ( اغلب به این دلیل است که CSP به یک Spider  مجهز است )

چه کسانی از CSP استفاده میکنند

عمده مرورگرها اکنون  از CSP HTTP header پشتیبانی میکنند. NWebSec استفاده از آن را در پروژه های MVC آسان کرده است. اکنون سایت های بزرگ از CSP  استفاده میکنند. اگر به سایتهای بزرگ مانند فیسبوک ،CNN، BBC،Google، Huffington Post ، Youtube، Twitter و GitHub سر بزنید و HTTP response آنها را چک کنید متوجه این موضوع خواهید شد.

افزونه های مرورگر و ISP

افزونه های مرورگر یا Extension ها و حتی ISP ها اسکریپتهایی را به صفحات وارد می کنند، که سبب گزارش نقض CSP  میشوند.CSP ممکن است بعضی از extension  های  مرورگر که در صفحات کد هایی را وارد کرده اند را شکسته یا تفکیک کند. اما آیا می توان به افزونه های مرورگر اعتماد کرد که در کدها تغییری ایجاد کنند ؟

شما میتوانید از SSL/TSL  که بیشتر فرم های ISP را با کدهای شما متوقف میکند استفاده کنید. پس CSP امنیت بیشتری به ما میدهد.

CSP و تبلیغات

تبلیغات می تواند یک مشکل برای CSP باشد. بعضی ارائه دهندگان تبلیغات بهتر از دیگران هستند. بعضی ها از منابعی استفاده میکنند که به طور مداوم در حال تغییر هستند که می تواند موجب خطای نقض  CSP شود . CNN تمام آگهی ها را درون Frame قرار می دهد که خبرها را یا حداقل آنهایی که قابل توجه هستند را بدون محدودیت CSP نشان می دهد.

ایجاد خودکار CSP

خزنده های خاص وب وجود دارند که ساخته شده اند برای خزیدن روی تمام لینکهای روی دامنه ، که برای تولید یک CSP policy به صورت خودکار تلاش میکنند. CSP Tools یک لیست از URLهایی که می توانند روی صفحات وب بخزند و CSP تولید کنند را گردآوری کرده است. روش دیگر این ابزار آن است که به گزارش خطای نقض CSP نگاه میکند و قوانینی بر اساس آنها می سازد.

بهترین راه آن است که هنگامی که سایت خود را می سازید، CSP خود را از پایه ایجاد کنید و سپس برای اطمینان از آن تست انجام دهید. می توانید CSP policy را روی حالت گزارش تنظیم کنید، پس مرورگر چیزی را مسدود نمیکند اما گزارش های خطای نقض را می دهد ، زمانی که از نبودن خطای نقض مطمئن شدید می توانید Policy  خود را بکار ببرید.

تست کردن CSP policy ها

افزونه CSP Tester کروم یک نمونه از ابزارهایی است که می توانید با استفاده از آن CSP policy  خود را در سایتتان بکار ببرید و تاثیر آن را در پنجره کنسول مرورگر ببینید. همانطور که گفته شد بهترین راه ، ایجاد CSP  درون سایتتان است. از دستور report-uri  برای پیدا کردن نقض ها و درست کردن آنها استفاده می شود. همچنین در سطح تست اگر از کار انجام شده اطمینان ندارید می توانید از Content-Security-Policy-Report-Only HTTP header بجای Content-Security-Policy برای متوقف کردن هر چیز توسط مرورگر استفاده کنید.