| <h1>Content Security Policy (CSP)</h1> |
| |
| |
| <p> |
| In order to mitigate a large class of potential 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="declare_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"><code>manifest.json</code></a> file as follows: |
| </p> |
| |
| <pre data-filename="manifest.json"> |
| { |
| ..., |
| "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>, and the <a href="http://www.html5rocks.com/en/tutorials/security/content-security-policy/"> |
| "An Introduction to Content Security Policy" |
| </a> article on HTML5Rocks. |
| </p> |
| |
| <h2 id="restrictions">Default Policy Restrictions</h2> |
| |
| <p> |
| Packages that do not define a <a href="manifestVersion"> |
| <code>manifest_version</code> |
| </a> have no default content security policy. Those that select |
| <code>manifest_version</code> 2, have a default content security policy |
| of: |
| </p> |
| |
| <pre>script-src 'self'; object-src 'self'</pre> |
| |
| <p> |
| This policy adds security by limiting extensions and applications in three |
| ways: |
| </p> |
| |
| <h3 id="JSEval">Eval and related functions are disabled</h3> |
| |
| <p>Code like the following does not work:</p> |
| |
| <pre> |
| alert(eval("foo.bar.baz")); |
| window.setTimeout("alert('hi')", 10); |
| window.setInterval("alert('hi')", 10); |
| new Function("return foo.bar.baz"); |
| </pre> |
| |
| <p>Evaluating strings of JavaScript like this is a common XSS attack vector. |
| Instead, you should write code like: |
| |
| <pre> |
| alert(foo && foo.bar && foo.bar.baz); |
| window.setTimeout(function() { alert('hi'); }, 10); |
| window.setInterval(function() { alert('hi'); }, 10); |
| function() { return foo && foo.bar && foo.bar.baz }; |
| </pre> |
| |
| <h3 id="JSExecution">Inline JavaScript will not be executed</h3> |
| |
| <p> |
| Inline JavaScript will not be executed. This restriction bans both inline |
| <code><script></code> blocks <strong>and</strong> inline event handlers |
| (e.g. <code><button onclick="..."></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#popups">Browser Action's popup</a> as a single |
| <code>popup.html</code> containing: |
| </p> |
| |
| <pre data-filename="popup.html"> |
| <!doctype html> |
| <html> |
| <head> |
| <title>My Awesome Popup!</title> |
| <script> |
| function awesome() { |
| // do something awesome! |
| } |
| |
| function totallyAwesome() { |
| // do something TOTALLY awesome! |
| } |
| |
| function clickHandler(element) { |
| setTimeout(<strong>"awesome(); totallyAwesome()"</strong>, 1000); |
| } |
| |
| function main() { |
| // Initialization work goes here. |
| } |
| </script> |
| </head> |
| <body onload="main();"> |
| <button <strong>onclick="clickHandler(this)"</strong>> |
| Click for awesomeness! |
| </button> |
| </body> |
| </html></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> |
| <p>The inline event handler definitions must be rewritten in terms of |
| <code>addEventListener</code> and extracted into <code>popup.js</code>.</p> |
| <p>If you're currently kicking off your program's execution via code like |
| <code><body onload="main();"></code>, consider replacing it by hooking |
| into the document's <code>DOMContentLoaded</code> event, or the window's |
| <code>load</code> event, depending on your needs. Below we'll use the |
| former, as it generally triggers more quickly.</p> |
| </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 data-filename="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); |
| } |
| |
| function main() { |
| // Initialization work goes here. |
| } |
| |
| // 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. |
| <strong>document.addEventListener('DOMContentLoaded', function () {</strong> |
| document.querySelector('button').addEventListener('click', clickHandler); |
| main(); |
| }); |
| </pre> |
| <pre data-filename="popup.html"> |
| <!doctype html> |
| <html> |
| <head> |
| <title>My Awesome Popup!</title> |
| <script <strong>src="popup.js"</strong>></script> |
| </head> |
| <body> |
| <button>Click for awesomeness!</button> |
| </body> |
| </html> |
| </pre> |
| |
| <p> |
| |
| |
| <h3 id="resourceLoading">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 data-filename="popup.html"> |
| <!doctype html> |
| <html> |
| <head> |
| <title>My Awesome Popup!</title> |
| <script src="<strong>http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js</strong>"></script> |
| </head> |
| <body> |
| <button>Click for awesomeness!</button> |
| </body> |
| </html> |
| </pre> |
| |
| <p> |
| Download the file, include it in your package, and write: |
| <p> |
| |
| <pre data-filename="popup.html"> |
| <!doctype html> |
| <html> |
| <head> |
| <title>My Awesome Popup!</title> |
| <script src="<strong>jquery.min.js</strong>"></script> |
| </head> |
| <body> |
| <button>Click for awesomeness!</button> |
| </body> |
| </html></pre> |
| |
| <h2 id="relaxing">Relaxing the default policy</h2> |
| |
| <h3 id="relaxing-inline-script">Inline Script</h3> |
| |
| <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. |
| </p> |
| |
| <h3 id="relaxing-remote-script">Remote Script</h3> |
| |
| <p> |
| If you have a need for some external JavaScript or object |
| resources, you can relax the policy to a limited extent by whitelisting |
| secure origins from which scripts should be accepted. We want to ensure that |
| executable resources loaded with an extension's elevated permissions are |
| exactly the resources you expect, and haven'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, those origins will |
| not be accepted. Currently, we allow whitelisting origins with the following |
| schemes: <code>HTTPS</code>, <code>chrome-extension</code>, and |
| <code>chrome-extension-resource</code>. |
| </p> |
| |
| <p> |
| To ease development, we're also allowing the whitelisting of resources loaded |
| over HTTP from servers on your local machine. You may whitelist script and |
| object sources on any port of either <code>http://127.0.0.1</code> or |
| <code>http://localhost</code>. |
| </p> |
| |
| <p class="note"> |
| The restriction against resources loaded over HTTP applies only to those |
| resources which are directly executed. You're still free, for example, to |
| make XMLHTTPRequest connections to any origin you like; the default policy |
| doesn't restrict <code>connect-src</code> or any of the other CSP directives |
| in any way. |
| </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 data-filename="manifest.json"> |
| "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#event-tracking-with-google-analytics">Event Tracking |
| with Google Analytics</a> sample extension, and a |
| <a href="tut_analytics">brief tutorial</a> that goes into more detail. |
| </p> |
| |
| <h3 id="relaxing-eval">Evaluated JavaScript</h3> |
| |
| <p> |
| The policy against <code>eval()</code> and its relatives like |
| <code>setTimeout(String)</code>, <code>setInterval(String)</code>, and |
| <code>new Function(String)</code> can be relaxed by adding |
| <code>'unsafe-eval'</code> to your policy: |
| </p> |
| |
| <pre data-filename="manifest.json"> |
| "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'" |
| </pre> |
| |
| <p> |
| However, we strongly recommend against doing this. These functions are |
| notorious XSS attack vectors. |
| </p> |
| |
| <h2 id="tightening">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#mappy">Mappy</a> sample |
| extension is a good example of an extension that's been locked down above and |
| beyond the defaults. |
| </p> |
| |
| |
| <h2 id="interactions">Content Scripts</h2> |
| |
| <p> |
| The policy that we have been discussing applies to the <a |
| href="background_pages">background pages</a> and <a href="event_pages">event |
| pages</a> of the extension. How they apply to the <a href="content_scripts"> |
| content scripts</a> of the extension is more complicated. |
| </p> |
| |
| <p> |
| Content scripts are generally not subject to the CSP of the extension. Since |
| content scripts are not HTML, the main impact of this is that they may use |
| <code>eval</code> even if the extension's CSP does not specify |
| <code>unsafe-eval</code>, although this is not recommended. Additionally, the |
| CSP of the <em>page</em> does not apply to content scripts. More complicated |
| are <code><script></code> tags that content scripts create and put into |
| the DOM of the page they are running on. We will refer to these as DOM |
| injected scripts going forward. |
| </p> |
| |
| <p> |
| DOM injected scripts that would be executed immediately upon injection into |
| the page will execute as you might expect. Imagine a content script with the |
| following code as a simple example: |
| <pre data-filename="content_script.js"> |
| document.write("<script>alert(1);</script>"); |
| </pre> |
| This content script will cause an <code>alert</code> immediately upon the |
| <code>document.write()</code>. Note that this will execute regardless of the |
| policy a page may specify. |
| </p> |
| |
| <p> |
| However, the behavior becomes more complicated both inside that DOM injected |
| script and for any script that does not immediately execute upon injection. |
| Imagine that our extension is running on a page that provides its own CSP |
| that specifies <code>script-src 'self'</code>. Now imagine the content script |
| executes the following code: |
| <pre data-filename="content_script.js"> |
| document.write("<button onclick='alert(1);'>click me</button>'"); |
| </pre> |
| If a user clicks on that button, the <code>onclick</code> script will |
| <em>not</em> execute. This is because the script did not immediately execute |
| and code not interpreted until the click event occurs is not considered part |
| of the content script, so the CSP <em>of the page</em> (not of the extension) |
| restricts its behavior. And since that CSP does not specify |
| <code>unsafe-inline</code>, the inline event handler is blocked. |
| </p> |
| |
| <p> |
| The correct way to implement the desired behavior in this case would be to add |
| the <code>onclick</code> handler as a function from the content script as |
| follows: |
| <pre data-filename="content_script.js"> |
| document.write("<button id='mybutton'>click me</button>'"); |
| var button = document.getElementById('mybutton'); |
| button.onclick = function() { |
| alert(1); |
| }; |
| </pre> |
| </p> |
| |
| <p> |
| Another similar issue arises if the content script executes the following: |
| <pre data-filename="content_script.js"> |
| var script = document.createElement('script'); |
| script.innerHTML = 'alert(1);' |
| document.getElementById('body').appendChild(script); |
| </pre> |
| In this case, the script <em>will</em> execute and the alert will pop up. |
| However, take this case: |
| <pre data-filename="content_script.js"> |
| var script = document.createElement('script'); |
| script.innerHTML = 'eval("alert(1);")'; |
| document.getElementById('body').appendChild(script); |
| </pre> |
| While the initial script will execute, the call to <code>eval</code> will be |
| blocked. That is, while the initial script execution is allowed, the behavior |
| within the script will be regulated by the page's CSP. |
| </p> |
| |
| <p> |
| Thus, depending on how you write DOM injected scripts in your extension, |
| changes to the page's CSP may affect the behavior of your extension. Since |
| content scripts are <em>not</em> affected by the page's CSP, this a great |
| reason to put as much behavior as possible of your extension into the content |
| script rather than DOM injected scripts. |
| </p> |