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:
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:
As you can see in the above code, I used following two headers for CSP implementation:
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!!!
To allow all outer scripts from SSL:
Firefox not only displays CSP Error but also CSP Warning:
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:
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:
- Attach HTTP headers for CSP with each response
- Save and preview all reports generated by the browser
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:
- "X-Content-Security-Policy" for Firefox
- "X-WebKit-CSP" for Chrome
... report-uri /Home/ReportThe "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:
connect-src
Limits the origins to which you can connect (via XHR, WebSockets, and EventSource).
font-src
Pecifies the origins that can serve web fonts. Google's Web Fonts could be enabled via font-src https://themes.googleusercontent.com
frame-src
Lists the origins that can be embedded as frames. For example: frame-src https://youtube.com would enable embedding YouTube videos, but no other origins.
media-src
Restricts the origins allowed to deliver video and audio.
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:
- http://www.w3.org/TR/CSP/
- https://wiki.mozilla.org/Security/CSP/Specification
- http://www.html5rocks.com/en/tutorials/security/content-security-policy/
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: