The security policy of the World Wide Web is rooted in the same-origin policy. For example, the code of www.jb51.net can only access the data of www.jb51.net, but does not have permission to access http://www.baidu.com. Each origin is isolated from the rest of the network, creating a secure sandbox for developers. This is perfect in theory, but now attackers have found clever ways to compromise this system.
This is an XSS cross-site scripting attack, which bypasses the same-origin policy through false content and decoy clicks. This is a big problem, and if an attacker successfully injects code, a considerable amount of user data can be leaked.
Now we introduce a new and effective security defense strategy to mitigate this risk, which is Content Security Policy (CSP).
Source Whitelist
The core of the XSS attack is that the browser cannot distinguish whether the script is injected by a third party or is really part of your application. For example, the Google 1 button will load and execute code from https://apis.google.com/js/plusone.js, but we cannot expect to determine from the picture on the browser that the code really comes from apis.google.com , again from apis.evil.example.com. The browser downloads and executes arbitrary code on page requests, regardless of its origin.
CSP defines the Content-Security-Policy HTTP header to allow you to create a whitelist of trusted sources so that the browser only executes and renders resources from these sources, rather than blindly trusting all content provided by the server. Even if an attacker can find a vulnerability to inject a script, it will not be executed because the source is not included in the whitelist.
Taking the Google 1 button above as an example, because we believe that apis.google.com provides valid code, as well as ourselves, we can define a policy that allows the browser to only execute scripts from one of the following two sources.
Content-Security-Policy:script-src 'self' https://apis.google.com
Isn’t it very simple? script-src can control script-related permissions for the specified page. This way the browser will only download and execute scripts from http://apis.google.com and this page itself.
Once we define this strategy, the browser will throw an error when it detects the injected code (note what browser it is).
Content security policy applies to all commonly used resources
Although script resources are the most obvious security risk, CSP also provides a rich set of instructions that allow the page to control the loading of various types of resources, such as the following types :
content-src: Limit the type of connection (such as XHR, WebSockets, and EventSource)
font-src: Control the source of web fonts. For example, Google's web fonts can be used through font-src https://themes.googleusercontent.com.
frame-src: Lists the sources of frames that can be embedded. For example, frame-src https://youtube.com only allows embedding of YouTube videos. .
img-src: Defines the source of loadable images.
media-src: Restrict video and audio sources.
object-src: Restrict the source of Flash and other plug-ins.
style-src: similar to Script-src, but only applies to css files.
By default, all settings are turned on without any restrictions. You can separate multiple directives with semicolons, but in the form script-src https://host1.com;script-src https://host2.com, the second directive will be ignored. The correct way to write it is script-src https://host1.com https://host2.com.
For example, if you have an application that needs to load all resources from a content delivery network (CDN, such as https://cdn.example.net), and you know that there is no content that does not require any frames or plug-ins, your strategy might be like As follows:
Content-Security-Policy:default-src https://cdn.example.net; frame-src 'none'; object-src 'none'
Details
I use in the example The HTTP header is Content-Security-Policy, but modern browsers already provide support via prefixes: Firefox uses x-Content-Security-Policy, WebKit uses X-WebKit-CSP. There will be a gradual transition to unified standards in the future.
Strategies can be set according to each different page, which provides great flexibility. Because some pages of your site may have Google 1 buttons, while others may not.
The source list for each directive can be quite flexible, you can specify the pattern (data:, https:), or specify the host name in a range (example.com, which matches any origin, any pattern and any port on the host ), or specify a complete URI (https://example.com:443, specifically https protocol, example.com domain name, port 443).
There are four more keywords you can use in your sources list:
"none": you might expect to match nothing
"self": the same as the current source, but without subdomains
"unsafe- inline": allows inline Javascript and CSS
"unsafe-eval": allows text-to-JS mechanisms such as eval
Please note that these keywords need to be quoted.
Sandbox
There is another directive worth discussing here: sandbox. It is somewhat inconsistent with other instructions. It mainly controls the actions taken on the page, rather than the resources that the page can load. If this attribute is set, the page will behave like a frame with the sandbox attribute set. This has a wide range of effects on the page, such as preventing form submissions, etc. This is a bit beyond the scope of this article, but you can find more information in the "Sandbox Flag Settings" chapter of the HTML5 specification.
Harmful Inline Code
CSP is based on source whitelisting, but it cannot solve the biggest source of XSS attacks: inline script injection. If an attacker can inject a script tag (
) that contains harmful code, the browser does not have a good mechanism to distinguish this tag. CSP can only solve this problem by disabling inline scripts completely. This prohibition includes not only script tags embedded in scripts, but also inline event handlers and javascrpt: URLs. You need to put the contents of the script tag into an external file and replace javascript: and
with the appropriate addEventListener methods. For example, you might rewrite the following form:
Am I amazing?
to the following form:
Am I amazing?
// amazing.js
function doAmazingThings() {
alert('YOU AM AMAZING!');
}
document.addEventListener('DOMContentReady', function () {
document.getElementById('amazing')
.addEventListener('click', doAmazingThings);
});
Whether using CSP or not, The above code actually has greater advantages. Inline JavaScript completely mixes structure and behavior, and you shouldn't do it. In addition, external resources are easier to cache by browsers, easier for developers to understand, and easier to compile and compress. If you use external code, you will write better code.
Inline styles need to be handled in the same way, both style attributes and style tags need to be extracted into external style sheets. This prevents all sorts of magical ways of data leakage.
If you must have inline scripts and styles, you can set the 'unsafe-inline value for the script-src or style-src attribute. But don’t do this. Disabling inline scripts is the greatest security guarantee provided by CSP. Disabling inline styles can make your application more secure and robust. It's a trade-off, but well worth it.
Eval
Even if the attacker cannot directly inject the script, he may trick your application into converting the inserted text into an executable script and executing itself. eval() , newFunction() , setTimeout([string], ...) and setInterval([string], ...) can all be vectors of this danger. CSP's strategy for this risk is to block these vectors entirely.
This has some implications for the way you build your applications:
Parse JSON via the built-in JSON.parse instead of relying on eval. Browsers after IE8 support local JSON operations, which is completely safe.
Rewrite the way you call setTimeout and setInterval by using inline functions instead of strings. For example:
setTimeout("document.querySelector('a').style.display = 'none';", 10);
Can be rewritten as:
setTimeout(function () { document.querySelector ('a').style.display = 'none'; }, 10);
Avoid inline templates at runtime: Many template libraries use new Function() to speed up template generation. This is great for dynamic programs, but risky for malicious text.
Reports<script>sendMyDataToEvilDotCom();</script> CSP’s ability to block untrusted resources on the server side is great for users, but it’s great for us to get the various notifications sent to the server so we can identify and fix any Malicious script injection. To do this, you can instruct the browser to send an interception report in JSON format to a certain address through the report-uri directive. <script><br /> function doAmazingThings() {<br /> alert('YOU AM AMAZING!');<br /> }<br /></script>Content-Security-Policy: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;The report will look like this:
{
"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"
}
}
The information contained in it will help you identify the interception situation, including the page where the interception occurred (document-uri), the referrer of the page, and the resources that violate the page policy ( blocked-uri), violated-directive, and all content security policies of the page (original-policy).
Real-world Usage
CSP is now available in Chrome 16 and Firefox 4, and it is expected to have limited support in IE10. Safari doesn't support it yet, but nightly builds of WebKit are available, so expect Safari to support it in the next iteration.
Let’s look at some common use cases:
Practical case 1: Social media widget
Google 1 button includes scripts from https://apis.google.com, and embedded from https:// iframe for plusone.google.com. Your strategy needs to include these sources to use the Google 1 button. The simplest strategy is script-src https://apis.google.com; frame-src https://plusone.google.com. You also need to make sure that the JS snippets provided by Google are stored in external JS files.
There are many implementation solutions for Facebook’s Like button. I recommend that you stick with the iframe version as it remains well isolated from the rest of your site. This requires using the frame-src https://facebook.com directive. Please note that by default, the iframe code provided by Facebook uses the relative path //facebook.com. Please change this code to https://facebook.com. You can not use HTTP if necessary.
Twitter’s Tweet button relies on script and frame, both coming from https://platform.twitter.com (Twitter provides relative URLs by default, please edit the code to specify HTTPS when copying).
Other platforms have similar situations and can be solved similarly. I recommend setting default-src to none, and then checking the console to check what resources you need to make sure the widget is working properly.
Using multiple widgets is very simple: just merge all the strategy directives and remember to keep the settings for the same directive together. If you want to use the three widgets above, the strategy will look like this:
script-src https://apis.google.com https://platform.twitter.com; frame-src https:// plusone.google.com https://facebook.com https://platform.twitter.com
Practical Case 2: Defense
Suppose you visit a bank website and want to ensure that only the resources you need are loaded. In this case, start by setting a default permission to block all content (default-src ‘none’) and build the policy from scratch.
For example, a bank website needs to load images, styles and scripts from the CDN from https://cdn.mybank.net, and connect to https://api.mybank.com/ through XHR to pull various data. You also need to use frames, but frames come from non-third-party local pages. There is no Flash, fonts and other content on the website. In this case, the strictest CSP header we can send is:
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; frame-src 'self'
Actual case 3: Only use SSL
A wedding ring forum administrator wants all resources to be loaded in a secure manner, but doesn't want to actually write too much code; rewriting a large number of third-party forum inline scripts and styles is beyond his capabilities. So the following policy will be very useful:
Content-Security-Policy: default-src https:; script-src https: 'unsafe-inline'; style-src https: 'unsafe-inline'
Although default-src specifies https, scripts and styles are not automatically inherited. Each directive will completely override the default resource type.
Future
The W3C’s Web Application Security Working Group is formulating the details of the content security policy specification. Version 1.0 is about to enter the final revision stage, and it is very close to what is described in this article. The public-webappsec@ mailing group is discussing version 1.1, and browser manufacturers are also working hard to consolidate and improve the implementation of CSP.
CSP 1.1 has some interesting features on the artboard that are worth listing separately:
Adding policies via meta tags: The preferred way to set CSP is through HTTP headers, which are very useful, but setting them via tags or scripts is more straightforward, but for now Not finalized yet. WebKit has implemented the feature of setting permissions through meta elements, so you can now try the following settings in Chrome: add
You can even add strategies via script at runtime.
DOM API: If the next iteration of CSP adds this feature, you can query the current security policy of the page through Javascript and adjust it according to different situations. For example, your code implementation may be slightly different if eval() is available. This is very useful for JS framework authors; and since the API specification is currently very uncertain, you can find the latest iteration in the Scripting Interface chapter of the draft specification.
New directives: Many new directives are being discussed, including script-nonce: only explicitly specified script elements can use inline scripts; plugin-types: this will limit the type of plugins; form-action: allows form to only Submit to a specific source.
If you are interested in discussions about these future features, you can read the mailing list archives or join the mailing list.
This article is translated from: http://www.html5rocks.com/en/tutorials/security/content-security-policy/
Excerpted from: Jiang Yujie’s blog