summaryrefslogtreecommitdiffstats
path: root/chrome/common/extensions/docs/static
diff options
context:
space:
mode:
authormkwst@chromium.org <mkwst@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-26 08:31:45 +0000
committermkwst@chromium.org <mkwst@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-26 08:31:45 +0000
commiteb77fe592eed618a37d3b73ba0dff5b1968b4efa (patch)
tree3db331c422b41b4f79719ac31e84fc196478f4da /chrome/common/extensions/docs/static
parent9d56027a1bd54cdf472fbc115688ebe24078e8d7 (diff)
downloadchromium_src-eb77fe592eed618a37d3b73ba0dff5b1968b4efa.zip
chromium_src-eb77fe592eed618a37d3b73ba0dff5b1968b4efa.tar.gz
chromium_src-eb77fe592eed618a37d3b73ba0dff5b1968b4efa.tar.bz2
Improving `content_security_policy` documentation.
Added a document just for `content_security_policy` explaining the default restrictions, and offering pointers regarding best practice. Also updated the Analytics example and documentation accordingly. BUG=111049 TEST= Review URL: https://chromiumcodereview.appspot.com/9212044 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@119211 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/common/extensions/docs/static')
-rw-r--r--chrome/common/extensions/docs/static/contentSecurityPolicy.html272
-rw-r--r--chrome/common/extensions/docs/static/manifest.html43
-rw-r--r--chrome/common/extensions/docs/static/tut_analytics.html89
3 files changed, 323 insertions, 81 deletions
diff --git a/chrome/common/extensions/docs/static/contentSecurityPolicy.html b/chrome/common/extensions/docs/static/contentSecurityPolicy.html
new file mode 100644
index 0000000..494387e
--- /dev/null
+++ b/chrome/common/extensions/docs/static/contentSecurityPolicy.html
@@ -0,0 +1,272 @@
+<div id="pageData-name" class="pageData">Content Security Policy (CSP)</div>
+<div id="pageData-showTOC" class="pageData">true</div>
+
+<p>
+ In order to mitigate a large class of potental cross-site scripting issues,
+ Chrome's extension system has incorporated the general concept of
+ <a href="http://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html">
+ <strong>Content Security Policy (CSP)</strong>
+ </a>. This introduces some fairly strict policies that will make extensions
+ more secure by default, and provides you with the ability to create and
+ enforce rules governing the types of content that can be loaded and executed
+ by your extensions and applications.
+</p>
+
+<p>
+ In general, CSP works as a black/whitelisting mechanism for resources loaded
+ or executed by your extensions. Defining a reasonable policy for your
+ extension enables you to carefully consider the resources that your extension
+ requires, and to ask the browser to ensure that those are the only resources
+ your extension has access to. These policies provide security over and above
+ the <a href="manifest.html#permissions">host permissions</a> your extension
+ requests; they're an additional layer of protection, not a replacement.
+</p>
+
+<p>
+ On the web, such a policy is defined via an HTTP header or <code>meta</code>
+ element. Inside Chrome's extension system, neither is an appropriate
+ mechanism. Instead, an extension's policy is defined via the extension's
+ <a href="manifest.html"><code>manifest.json</code></a> file as follows:
+</p>
+
+<pre>{
+ ...,
+ "content_security_policy": "[POLICY STRING GOES HERE]"
+ ...
+}</pre>
+
+<p class="note">
+ For full details regarding CSP's syntax, please take a look at
+ <a href="http://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html#syntax">
+ the Content Security Policy specification
+ </a>.
+</p>
+
+<h2>Default Policy Restrictions</h2>
+
+<p>
+ By default, Chrome defines a content security policy of:
+</p>
+
+<pre>script-src 'self'; object-src 'self'</pre>
+
+<p>
+ This policy limits extensions in two ways:
+</p>
+
+<h3>Inline JavaScript will not be executed</h3>
+
+<p>
+ Inline JavaScript, as well as dangerous string-to-JavaScript methods like
+ <code>eval</code>, will not be executed. This restriction bans both inline
+ <code>&lt;script&gt;</code> blocks <strong>and</strong> inline event handlers
+ (e.g. <code>&lt;button onclick="..."&gt;</code>).
+</p>
+
+<p>
+ The first restriction wipes out a huge class of cross-site scripting attacks
+ by making it impossible for you to accidentally execute script provided by a
+ malicious third-party. It does, however, require you to write your code with a
+ clean separation between content and behavior (which you should of course do
+ anyway, right?). An example might make this clearer. You might try to write a
+ <a href="browserAction.html#popups">Browser Action's popup</a> as a single
+ <code>popup.html</code> containing:
+</p>
+
+<pre>&lt;!doctype html&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;title&gt;My Awesome Popup!&lt;/title&gt;
+ &lt;script&gt;
+ function awesome() {
+ // do something awesome!
+ }
+
+ function totallyAwesome() {
+ // do something TOTALLY awesome!
+ }
+
+ function clickHandler(element) {
+ setTimeout(<strong>"awesome(); totallyAwesome()"</strong>, 1000);
+ }
+ &lt;/script&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+ &lt;button <strong>onclick="clickHandler(this)"</strong>&gt;
+ Click for awesomeness!
+ &lt;/button&gt;
+ &lt;/body&gt;
+&lt;/html&gt;</pre>
+
+<p>
+ Three things will need to change in order to make this work the way you expect
+ it to:
+</p>
+
+<ul>
+ <li>
+ The <code>clickHandler</code> definition needs to move into an external
+ JavaScript file (<code>popup.js</code> would be a good target).
+ </li>
+ <li>
+ The inline event handler definition must be rewritten in terms of
+ <code>addEventListener</code> and extracted into <code>popup.js</code>.
+ </li>
+ <li>
+ The <code>setTimeout</code> call will need to be rewritten to avoid
+ converting the string <code>"awesome(); totallyAwesome()"</code> into
+ JavaScript for execution.
+ </li>
+</ul>
+
+<p>
+ Those changes might look something like the following:
+</p>
+
+<pre>popup.js:
+=========
+
+function awesome() {
+ // Do something awesome!
+}
+
+function totallyAwesome() {
+ // do something TOTALLY awesome!
+}
+
+<strong>
+function awesomeTask() {
+ awesome();
+ totallyAwesome();
+}
+</strong>
+
+function clickHandler(e) {
+ setTimeout(<strong>awesomeTask</strong>, 1000);
+}
+
+// Add event listeners once the DOM has fully loaded by listening for the
+// `DOMContentLoaded` event on the document, and adding your listeners to
+// specific elements when it triggers.
+document.addEventListener('DOMContentLoaded', function () {
+ document.querySelector('button').addEventListener('click', clickHandler);
+});
+
+popup.html:
+===========
+
+&lt;!doctype html&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;title&gt;My Awesome Popup!&lt;/title&gt;
+ &lt;script <strong>src="popup.js"</strong>&gt;&lt;/script&gt;
+ &lt;/script&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+ &lt;button&gt;Click for awesomeness!&lt;/button&gt;
+ &lt;/body&gt;
+&lt;/html&gt;</pre>
+
+<p>
+
+
+<h3>Only local script and and object resources are loaded</h3>
+
+<p>
+ Script and object resources can only be loaded from the extension's
+ package, not from the web at large. This ensures that your extension only
+ executes the code you've specifically approved, preventing an active network
+ attacker from maliciously redirecting your request for a resource.
+</p>
+
+<p>
+ Instead of writing code that depends on jQuery (or any other library) loading
+ from an external CDN, consider including the specific version of jQuery in
+ your extension package. That is, instead of:
+</p>
+
+<pre>&lt;!doctype html&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;title&gt;My Awesome Popup!&lt;/title&gt;
+ &lt;script src="<strong>http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js</strong>"&gt;&lt;/script&gt;
+ &lt;/script&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+ &lt;button&gt;Click for awesomeness!&lt;/button&gt;
+ &lt;/body&gt;
+&lt;/html&gt;</pre>
+
+<p>
+ Download the file, include it in your package, and write:
+<p>
+
+<pre>&lt;!doctype html&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;title&gt;My Awesome Popup!&lt;/title&gt;
+ &lt;script src="<strong>jquery.min.js</strong>"&gt;&lt;/script&gt;
+ &lt;/script&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+ &lt;button&gt;Click for awesomeness!&lt;/button&gt;
+ &lt;/body&gt;
+&lt;/html&gt;</pre>
+
+<h2>Relaxing the default policy</h2>
+
+<p>
+ There is no mechanism for relaxing the restriction against executing inline
+ JavaScript. In particular, setting a script policy that includes
+ <code>unsafe-inline</code> will have no effect. This is intentional.
+</p>
+
+<p>
+ If, on the other hand, you have a need for some external JavaScript or object
+ resources, you can relax the policy to a limited extent by whitelisting
+ specific HTTPS origins from which scripts should be accepted. Whitelisting
+ insecure HTTP resources will have no effect. This is intentional, because
+ we want to ensure that executable resources loaded with an extension's
+ elevated permissions is exactly the resource you expect, and hasn't been
+ replaced by an active network attacker. As <a
+ href="http://en.wikipedia.org/wiki/Man-in-the-middle_attack">man-in-the-middle
+ attacks</a> are both trivial and undetectable over HTTP, only HTTPS origins
+ will be accepted.
+</p>
+
+<p>
+ A relaxed policy definition which allows script resources to be loaded from
+ <code>example.com</code> over HTTPS might look like:
+</p>
+
+<pre>{
+ ...,
+ "content_security_policy": "script-src 'self' https://example.com; object-src 'self'",
+ ...
+}</pre>
+
+<p class="note">
+ Note that both <code>script-src</code> and <code>object-src</code> are defined
+ by the policy. Chrome will not accept a policy that doesn't limit each of
+ these values to (at least) <code>'self'</code>.
+</p>
+
+<p>
+ Making use of Google Analytics is the canonical example for this sort of
+ policy definition. It's common enough that we've provided an Analytics
+ boilerplate of sorts in the <a href="samples.html#analytics">Event Tracking
+ with Google Analytics</a> sample extension, and a
+<a href="tut_analytics.html">brief tutorial</a> that goes into more detail.
+</p>
+
+<h2>Tightening the default policy</h2>
+
+<p>
+ You may, of course, tighten this policy to whatever extent your extension
+ allows in order to increase security at the expense of convenience. To specify
+ that your extension can only load resources of <em>any</em> type (images, etc)
+ from its own package, for example, a policy of <code>default-src 'self'</code>
+ would be appropriate. The <a href="samples.html#mappy">Mappy</a> sample
+ extension is a good example of an extension that's been locked down above and
+ beyond the defaults.
+</p>
diff --git a/chrome/common/extensions/docs/static/manifest.html b/chrome/common/extensions/docs/static/manifest.html
index d05cdaa..2e58812 100644
--- a/chrome/common/extensions/docs/static/manifest.html
+++ b/chrome/common/extensions/docs/static/manifest.html
@@ -39,7 +39,7 @@ are <b>name</b> and <b>version</b>.
"<a href="background_pages.html">background</a>": {...},
"<a href="override.html">chrome_url_overrides</a>": {...},
"<a href="content_scripts.html">content_scripts</a>": [...],
- "<a href="#content_security_policy">content_security_policy</a>": "<em>policyString</em>",
+ "<a href="contentSecurityPolicy.html">content_security_policy</a>": "<em>policyString</em>",
"<a href="fileBrowserHandler.html">file_browser_handlers</a>": [...],
"<a href="#homepage_url">homepage_url</a>": "http://<em>path/to/homepage</em>",
"<a href="#incognito">incognito</a>": "spanning" <em>or</em> "split",
@@ -111,47 +111,6 @@ You can specify locale-specific strings for this field;
see <a href="i18n.html">Internationalization</a> for details.
</p>
-<h3 id="content_security_policy">content_security_policy</h3>
-
-<p>
-A security policy to apply to resources in your extension. You can use this
-policy to help prevent cross-site scripting vulnerabilities in your extension.
-By default, the extension system enforces the following policy:
-</p>
-
-<pre>script-src 'self'; object-src 'self'</pre>
-
-<p>
-Extensions can tighten their policy using the
-<code>content_security_policy</code> manifest attribute. For example, to
-specify that your extension loads resources only from its own package, use the
-following policy:
-</p>
-
-<pre>"content_security_policy": "default-src 'self' " </pre>
-
-<p>
-If you need to load resources from websites,
-you can add them to the whitelist.
-For example, if your extension uses Google Analytics,
-you might use the following policy:
-</p>
-
-<pre>"content_security_policy": "default-src 'self' https://ssl.google-analytics.com"</pre>
-
-<p>
-The extension system will prevent you including insecure resources
-for <code>script-src</code> or <code>object-src</code>. If you are using
-<code>eval</code> to parse JSON, please consider using <code>JSON.parse</code>
-instead.
-</p>
-
-<p>
-For details, see the
-<a href="http://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html">Content Security Policy specification</a>.
-</p>
-
-
<h3 id="homepage_url">homepage_url</h3>
<p>
diff --git a/chrome/common/extensions/docs/static/tut_analytics.html b/chrome/common/extensions/docs/static/tut_analytics.html
index f1a8bc1..88c3f95 100644
--- a/chrome/common/extensions/docs/static/tut_analytics.html
+++ b/chrome/common/extensions/docs/static/tut_analytics.html
@@ -13,7 +13,7 @@ extension.</p>
<p>
You will also need a <a href="http://www.google.com/analytics">Google
- Analytics account</a> set up to track your extension. Note that when setting
+ Analytics account</a> set up to track your extension. Note that when setting
up the account, you can use any value in the Website's URL field, as your
extension will not have an URL of its own.
</p>
@@ -24,26 +24,20 @@ extension.</p>
alt="The analytics setup with info for a chrome extension filled out." />
</p>
-<p>
- Also note that Google Analytics requires version <strong>4.0.302.2</strong>
- of Google Chrome to work correctly. Users with an earlier version of Google
- Chrome will not show up on your Google Analytics reports. View
- <a href="faq.html#faq-dev-14">this FAQ entry</a> to learn how to check which
- version of Google Chrome is deployed to which platform.
-</p>
-
<h2 id="toc-installing">Installing the tracking code</h2>
<p>
The standard Google Analytics tracking code snippet fetches a file named
<code>ga.js</code> from an SSL protected URL if the current page
- was loaded using the <code>https://</code> protocol. <strong>It is strongly
- advised to use the SSL protected ga.js in an extension</strong>,
- but Google Chrome extension
- pages are hosted under <code>chrome-extension://</code> URLs, so the tracking
- snippet must be modified slightly to pull <code>ga.js</code> directly from
- <code>https://ssl.google-analytics.com/ga.js</code> instead of the default
- location.
+ was loaded using the <code>https://</code> protocol. <strong>Chrome
+ extensions and applications may <em>only</em> use the SSL-protected version of
+ <code>ga.js</code></strong>. Loading <code>ga.js</code> over insecure HTTP is
+ disallowed by Chrome's default <a href="contentSecurityPolicy.html">Content
+ Security Policy</a>. This, plus the fact that Chrome extensions are hosted
+ under the <code>chrome-extension://</code> schema, requires a slight
+ modification to the usual tracking snippet to pull <code>ga.js</code> directly
+ from <code>https://ssl.google-analytics.com/ga.js</code> instead of the
+ default location.
</p>
<p>
@@ -61,29 +55,45 @@ extension.</p>
</pre>
<p>
- Here is a background page which loads the asynchronous tracking code and
+ You'll also need to ensure that your extension has access to load the resource
+ by relaxing the default content security policy. The policy definition in your
+ <a href="manifest.html"><code>manifest.json</code></a> might look like:
+</p>
+
+<pre>{
+ ...,
+ "content_security_policy": "script-src 'self' https://ssl.google-analytics.com; object-src 'self'",
+ ...
+}</pre>
+
+<p>
+ Here is a popup page (<code>popup.html</code>) which loads the asynchronous
+ tracking code via an external JavaScript file (<code>popup.js</code>) and
tracks a single page view:
</p>
-<pre>
+<pre>popup.js:
+=========
+
+var _gaq = _gaq || [];
+_gaq.push(['_setAccount', 'UA-XXXXXXXX-X']);
+_gaq.push(['_trackPageview']);
+
+(function() {
+ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+ ga.src = 'https://ssl.google-analytics.com/ga.js';
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+})();
+
+popup.html:
+===========
&lt;!DOCTYPE html>
&lt;html>
&lt;head>
...
+ &lt;script src="popup.js">&lt;/script>
&lt;/head>
&lt;body>
- &lt;script>
- var _gaq = _gaq || [];
- _gaq.push(['_setAccount', 'UA-XXXXXXXX-X']);
- _gaq.push(['_trackPageview']);
-
- (function() {
- var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
- ga.src = 'https://ssl.google-analytics.com/ga.js';
- var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
- })();
- &lt;/script>
-
...
&lt;/body>
&lt;/html>
@@ -142,9 +152,9 @@ extension.</p>
</p>
<pre>
- &lt;button>Button 1&lt;/button>
- &lt;button>Button 2&lt;/button>
- &lt;button>Button 3&lt;/button>
+ &lt;button id='button1'>Button 1&lt;/button>
+ &lt;button id='button2'>Button 2&lt;/button>
+ &lt;button id='button3'>Button 3&lt;/button>
</pre>
<p>
@@ -152,19 +162,20 @@ extension.</p>
</p>
<pre>
- function trackButton(button_id) {
- _gaq.push(['_trackEvent', 'button' + button_id, 'clicked']);
+ function trackButton(e) {
+ _gaq.push(['_trackEvent', e.target.id, 'clicked']);
};
</pre>
<p>
- And call it when each button is pressed:
+ And use it as an event handler for each button's click:
</p>
<pre>
- &lt;button onclick="trackButton(1);">Button 1&lt;/button>
- &lt;button onclick="trackButton(2);">Button 2&lt;/button>
- &lt;button onclick="trackButton(3);">Button 3&lt;/button>
+ var buttons = document.querySelectorAll('button');
+ for (var i = 0; i < buttons.length; i++) {
+ buttons[i].addEventListener('click', trackButtonClick);
+ }
</pre>
<p>