Skip to main content

Exploring CSP (Content Security Policy) using ASP.NET MVC

In this post, I'll practically show you one promising new defense using CSP (Content Security Policy) that can significantly reduce possible XSS (Cross-Site Scripting) attacks in modern web-browsers (currently Chrome 16+ and Firefox 4+)!

I'll not only block inline/outer scripts but also ask user-agent to auto-generate report for each violated activity it founds that violates my pre-defined policy.

I created an ASP.NET MVC demo app; which is aimed to:
  1. Attach HTTP headers for CSP with each response
  2. Save and preview all reports generated by the browser
                      Download Demo Project

Here is how Google Chrome blocks unallowed scripts:

And the Firefox is blocking unallowed scripts as well:

Here is how Google Chrome generates a report to pre-defined 'report-uri' directive and passes data as 'application/json':

To append CSP headers for each response; we'll add code in "Application_BeginRequest" method in "MvcApplication" class under "Global.asax" file:

void Application_BeginRequest(object sender, EventArgs ex)
    /* ======== For Chrome ======== */
    Response.AddHeader("X-WebKit-CSP", "default-src 'self'; img-src *; script-src 'self'; style-src 'self' 'unsafe-inline'; report-uri /Home/Report");

    /* ======== For Firefox ======== */
    Response.AddHeader("X-Content-Security-Policy", "default-src 'self'; img-src *; script-src 'self'; style-src 'self' 'unsafe-inline'; report-uri /Home/Report");

As you can see in the above code, I used following two headers for CSP implementation:
  1. "X-Content-Security-Policy" for Firefox
  2. "X-WebKit-CSP" for Chrome
I used 'report-uri' directive to instruct the browser to notify me about any activity that violates my pre-defined policies.

... report-uri /Home/Report

The "Report" action method looks like this:

public JsonResult Report() { return Json(true); }

Remember, POST/GET doesn't matter for this action method! Also the browser will totally ignore what you return with this action. Because: "User Agents MUST NOT honor HTTP 3xx response codes to prevent HTTP header leakage across domains."

I'm blocking all inline as well as outer scripts for possible security gain; however I'm allowing inline-styles because it is difficult for me to not use inline-styles!!!

...; script-src 'self'; style-src 'self' 'unsafe-inline'; ...

"Banning inline script is the biggest security win CSP provides, and banning inline style likewise hardens your application."

To allow all outer scripts from SSL:

script-src https:

To allow inline scripts as well:

script-src https: 'unsafe-inline'

Instead of blocking any resource; you can use report-only header to ONLY get notified of violated activities:

/* ======== For Chrome ======== */
Response.AddHeader("X-WebKit-CSP-Report-Only", "...; report-uri /Home/Report");

/* ======== For Firefox ======== */
Response.AddHeader("X-Content-Security-Policy-Report-Only", "...; report-uri /Home/Report");

"The policy specified in report-only mode won't block restricted resources, but it will send violation reports to the location you specify."

img-src *

I'm also allowing images from all locations (http/https) by using asterisk (*) symbol. To restrict SSL only domains for images:

img-src https: *

Or to allow self-domain ONLY for images:

img-src 'self'

There as so many other directives that you can use to get full control over content that was not possible yesterday. For example, you can use:

  1. connect-src
    Limits the origins to which you can connect (via XHR, WebSockets, and EventSource).

  2. font-src
    Pecifies the origins that can serve web fonts. Google's Web Fonts could be enabled via font-src

  3. frame-src
    Lists the origins that can be embedded as frames. For example: frame-src would enable embedding YouTube videos, but no other origins.

  4. media-src
    Restricts the origins allowed to deliver video and audio.

  5. object-src
    Allows control over Flash and other plugins.

Firefox's Behavior regarding CSP

Firefox fails to recognize/parse 'unsafe-inline' source as show in the following figure:

Firefox not only displays CSP Error but also CSP Warning:

CSP ERROR: Couldn't parse invalid source 'unsafe-inline'
CSP WARN: Failed to parse unrecoginzied source 'unsafe-inline'

Firefox is also NOT appending 'document-uri' directive in the report.

Firefox absolute-links the 'blocked-uri' however Google Chrome just appends the origin only.

For "inline script base restriction"; Firefox uses 'self' as 'blocked-uri' value however Google Chrome ignores it.

For further reading:
Updated at: Jan 15, 2012

Unprefixed support for Content Security Policy in Chrome 25 Beta
Content Security Policy (CSP) helps you reduce the risk of cross-site scripting and other content injection attacks. Starting in today’s Beta release, you can use the unprefixed Content-Security-Policy HTTP header to define a whitelist of trusted content sources. The browser will only execute or render resources from those sources. For example:

Popular posts from this blog

Save files on disk using JavaScript or JQuery!

You can save any file, or DataURL, or Blob on disk using HTML5's newly introduced "download" attribute.

Use cases:

1. Force browser to download/save files like PDF/HTML/PHP/ASPX/JS/CSS/etc. on disk
2. Concatenate all transmitted blobs and save them as file on disk - it is useful in file sharing applications

Microsoft Edge? (msSaveBlob/msSaveOrOpenBlob)

/** * @param {Blob} file - File or Blob object. This parameter is required. * @param {string} fileName - Optional file name e.g. "image.png" */functioninvokeSaveAsDialog(file, fileName){if(!file){throw'Blob object is required.'; }if(!file.type){ file.type ='video/webm'; }var fileExtension = file.type.split('/')[1]; if(fileName && fileName.indexOf('.')!==-1){var splitted = fileName.split('.'); fileName = splitted[0]; fileExtension = splitted[1]; }var fileFullName …

Disable ICE Trickling

ICE trickling is a process where candidate-pairs are shared as soon as gathered by the ICEAgent.

Its true that, there is NO JavaScript API "currently" available in RTCWeb drafts to disable ICE-trickling process however, there is a trick that can be used to merge all candidate pairs in the session-description, and then you merely need to share that "single" SDP only.

The trick is simple: Wait until "end-of-candidate" signal is fired.

Usually "onicecandidate" event returns "NULL" entry for "event.candidate" object.

In "old-good" days, we were watching for "oniceconnectionstatechange" event, and checking for "peer.iceGatheringState === 'complete'" to return the SDP.

BTW, you can still listen for both "end-of-candidate" NULL value, as well as "peer.iceGatheringState === 'complete'".

peer.oniceconnectionstatechange =function(event){if(peer.iceGatheringState ==='…

WebRTC Tips & Tricks

This blog post is added for WebRTC newbies and beginners who wanna learn key-ideas; get code snippets and enjoy WebRTC life!

1. How to mute/unmute media streams?Remember, mute/unmute isn't implemented as a default/native features in either media capturing draft i.e. getUserMedia API also in WebRTC draft i.e. RTCPeerConnection API.

Also, there is no "onmuted" and "onunmuted" event defined or fired in the WebRTC native implementations.

Usually, as per chromium team's suggestions, media-tracks are enabled/disabled to mute/unmute the streams.

Remember, "MediaStreamTrack.enabled=false" NEVER sends silence audio or blank/black video; it doesn't stop packet transmission. Although when you set "MediaStreamTracks.enabled=false", packets are devoid of meaningful data. A solution for this approach is to hold/unhold tracks from SDP and renegotiate the connections. See next section for more information.

MediaStream object is just a synchronous conta…