|
1 |
| -# Explainer for the TODO API |
| 1 | +# Explainer for script-src-v2 |
2 | 2 |
|
3 |
| -**Instructions for the explainer author: Search for "todo" in this repository and update all the |
4 |
| -instances as appropriate. For the instances in `index.bs`, update the repository name, but you can |
5 |
| -leave the rest until you start the specification. Then delete the TODOs and this block of text.** |
6 |
| - |
7 |
| -This proposal is an early design sketch by [TODO: team] to describe the problem below and solicit |
| 3 | +This proposal is an early design sketch by the Chrome Secure Web and Network team to describe the problem below and solicit |
8 | 4 | feedback on the proposed solution. It has not been approved to ship in Chrome.
|
9 | 5 |
|
10 |
| -TODO: Fill in the whole explainer template below using https://tag.w3.org/explainers/ as a |
11 |
| -reference. Look for [brackets]. |
12 |
| - |
13 | 6 | ## Proponents
|
14 | 7 |
|
15 |
| -- [Proponent team 1] |
16 |
| -- [Proponent team 2] |
17 |
| -- [etc.] |
| 8 | +- Chrome Secure Web and Network team |
18 | 9 |
|
19 | 10 | ## Participate
|
20 |
| -- https://github.com/explainers-by-googlers/[your-repository-name]/issues |
21 |
| -- [Discussion forum] |
| 11 | +- https://github.com/explainers-by-googlers/script-src-v2/issues |
22 | 12 |
|
23 |
| -## Table of Contents [if the explainer is longer than one printed page] |
| 13 | +## Table of Contents |
24 | 14 |
|
25 | 15 | <!-- Update this table of contents by running `npx doctoc README.md` -->
|
26 | 16 | <!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
@@ -50,128 +40,184 @@ reference. Look for [brackets].
|
50 | 40 |
|
51 | 41 | ## Introduction
|
52 | 42 |
|
53 |
| -[The "executive summary" or "abstract". |
54 |
| -Explain in a few sentences what the goals of the project are, |
55 |
| -and a brief overview of how the solution works. |
56 |
| -This should be no more than 1-2 paragraphs.] |
| 43 | +We're proposing a new CSP directive to help websites protect themselves against DOM XSS. Developers will be able to allowlist scripts that are allowed to execute through the existing hashes mechanism, that will now extend to cover [script-src](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src) URLs and [eval](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval). This facilitates an easier to deploy, robust CSP policy that mitigates XSS by blocking unallowed inline and eval scripts. |
57 | 44 |
|
58 |
| -## Goals |
| 45 | +To be secure, a policy needs to permit legitimate scripts to execute, while blocking any scripts that the application doesn't expect. In practice, this means avoiding host-based allowlists and having a strict CSP allowing the execution of scripts by using nonces or hashes. |
59 | 46 |
|
60 |
| -[What is the **end-user need** which this project aims to address? Make this section short, and |
61 |
| -elaborate in the Use cases section.] |
| 47 | +To be easy-to-deploy, a policy should ideally not require developers to make any changes to their application other than adding CSP (usually via an HTTP header or <meta> tag). |
62 | 48 |
|
63 |
| -## Non-goals |
64 | 49 |
|
65 |
| -[If there are "adjacent" goals which may appear to be in scope but aren't, |
66 |
| -enumerate them here. This section may be fleshed out as your design progresses and you encounter necessary technical and other trade-offs.] |
| 50 | +## **Goals** |
67 | 51 |
|
68 |
| -## User research |
69 | 52 |
|
70 |
| -[If any user research has been conducted to inform your design choices, |
71 |
| -discuss the process and findings. User research should be more common than it is.] |
72 | 53 |
|
73 |
| -## Use cases |
| 54 | +* Allow sites to protect themselves from XSS attacks, even if they rely on scripts loaded via eval, or scripts loaded via script-src that change often (i.e. cases where SRI is impractical). |
| 55 | +* Provide a safe alternative for sites that currently use <code>[unsafe-eval](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src#unsafe_eval_expressions)</code>. |
| 56 | +* Implement this in a backwards compatible way, so websites can use it without causing breakage for users of browsers that don’t yet support the feature. |
74 | 57 |
|
75 |
| -[Describe in detail what problems end-users are facing, which this project is trying to solve. A |
76 |
| -common mistake in this section is to take a web developer's or server operator's perspective, which |
77 |
| -makes reviewers worry that the proposal will violate [RFC 8890, The Internet is for End |
78 |
| -Users](https://www.rfc-editor.org/rfc/rfc8890).] |
79 | 58 |
|
80 |
| -### Use case 1 |
| 59 | +## <strong>Non-goals</strong> |
81 | 60 |
|
82 |
| -### Use case 2 |
83 | 61 |
|
84 |
| -<!-- In your initial explainer, you shouldn't be attached or appear attached to any of the potential |
85 |
| -solutions you describe below this. --> |
86 | 62 |
|
87 |
| -## [Potential Solution] |
| 63 | +* Deprecate unsafe-eval (or any other existing CSP directives). |
88 | 64 |
|
89 |
| -[For each related element of the proposed solution - be it an additional JS method, a new object, a new element, a new concept etc., create a section which briefly describes it.] |
90 | 65 |
|
91 |
| -```js |
92 |
| -// Provide example code - not IDL - demonstrating the design of the feature. |
| 66 | +## **Use cases** |
93 | 67 |
|
94 |
| -// If this API can be used on its own to address a user need, |
95 |
| -// link it back to one of the scenarios in the goals section. |
| 68 | +XSS is arguably the most dangerous vulnerability class affecting web services for the past 15 years. Content Security Policy was created as a defense-in-depth mechanism to ensure that even when a document suffers from HTML injection, and thus contains arbitrary markup controlled by an attacker, the application will be protected from the execution of untrusted scripts. |
96 | 69 |
|
97 |
| -// If you need to show how to get the feature set up |
98 |
| -// (initialized, or using permissions, etc.), include that too. |
99 |
| -``` |
| 70 | +The core challenge for CSP is to distinguish between legitimate scripts (intended by the author of the page to execute and usually necessary for an application to function properly) and malicious scripts (potentially injected by an attacker via an HTML injection bug, for example, if a developer has neglected to appropriately escape attacker-controlled data when embedding it in their HTML). |
100 | 71 |
|
101 |
| -[Where necessary, provide links to longer explanations of the relevant pre-existing concepts and API. |
102 |
| -If there is no suitable external documentation, you might like to provide supplementary information as an appendix in this document, and provide an internal link where appropriate.] |
103 | 72 |
|
104 |
| -[If this is already specced, link to the relevant section of the spec.] |
| 73 | +### Allowlisting specific URLs for use with script-src |
105 | 74 |
|
106 |
| -[If spec work is in progress, link to the PR or draft of the spec.] |
| 75 | +Sites that want to allowlist specific scripts for use with script-src currently have 2 options, allowlist the specific scripts contents through [subresource integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity), which is not practical for scripts that change often (e.g. analytics scripts), or use [host-source](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy#host-source) to allowlist hostnames, which has the issues [described in further detail below](?tab=t.0#bookmark=id.i59bvq2i29zz). These issues would be addressed if we have a mechanism to allowlist full URLs for script-src. |
107 | 76 |
|
108 |
| -[If you have more potential solutions in mind, add ## Potential Solution 2, 3, etc. sections.] |
109 | 77 |
|
110 |
| -### How this solution would solve the use cases |
| 78 | +### Allowlisting specific scripts for use with `eval` or `Function` |
111 | 79 |
|
112 |
| -[If there are a suite of interacting APIs, show how they work together to solve the use cases described.] |
| 80 | +The only existing mechanism to use eval or Function is by enabling them with [unsafe-eval](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src#unsafe_eval_expressions), which allows all scripts. This means that currently any site that needs to use eval must expose itself to eval-based XSS risks. Allowlisting individual scripts would prevent this risk. |
113 | 81 |
|
114 |
| -#### Use case 1 |
115 | 82 |
|
116 |
| -[Description of the end-user scenario] |
| 83 | +## **Proposed Solution** |
117 | 84 |
|
118 |
| -```js |
119 |
| -// Sample code demonstrating how to use these APIs to address that scenario. |
120 |
| -``` |
121 | 85 |
|
122 |
| -#### Use case 2 |
| 86 | +### Add new CSP directive |
| 87 | + |
| 88 | +Since this proposal adds new ways to allowlist scripts, it would run into backwards compatibility issues in browsers that do not yet support it (e.g. a developer allowlists a URL they’re using in script-src, this will work in browsers that support the new functionality, but will be blocked in older browsers that do not). To address this, we propose adding a new “script-src-v2”\* directive to support the new features. This way sites can add a fallback more permissive script-src (e.g. https: or unsafe-eval) directive that older browsers (which don’t support “script-src-v2” and will ignore it) can fall back to. |
| 89 | + |
| 90 | +\*The naming aims to capture that this is meant to improve coverage of script-src, however this directive does not fully replace script-src, as it doesn’t cover all of what script-src does. |
| 91 | + |
| 92 | +This new directive would support a subset of what script-srcs covers, namely: |
| 93 | + |
| 94 | + |
| 95 | + |
| 96 | +* [nonce](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy#nonce-nonce_value) |
| 97 | +* [<hash_algorithm>-<hash_value>](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy#hash_algorithm-hash_value) (which will now cover eval) |
| 98 | +* [unsafe-hashes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy#unsafe-hashes) |
| 99 | +* [strict-dynamic](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy#strict-dynamic) |
| 100 | +* [unsafe-inline](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy#unsafe-inline) |
| 101 | +* [unsafe-eval](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy#unsafe-eval) |
| 102 | +* The new url-hashes keyword, which will cover script-src URLs, as described in the next section |
| 103 | + |
| 104 | +A point of discussion is whether script-src-v2 replaces script-src if both are set, or we try to enforce both at the same time (see detailed design section below). |
| 105 | + |
| 106 | + |
| 107 | +### Introduce new url-hashes keyword to cover script-src attributes |
| 108 | + |
| 109 | +Currently, if the CSP header is set, scripts loaded via script-src need to be allowlisted, which can only be done through [nonces](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy#nonce-nonce_value) or SRI. This proposes adding a mechanism to allowlist individual URLs (the initial URL, without following redirects, since following redirects would cause a XSLeak, by exposing whether the URL triggers a redirect) via their hash by adding a new ‘url-hashes’ expression that can be added to script-src.This new url-hashes directive would support both absolute and relative URLs, e.g.: |
123 | 110 |
|
124 |
| -[etc.] |
125 | 111 |
|
126 |
| -## Detailed design discussion |
| 112 | +``` |
| 113 | +Content-Security-Policy: script-src 'url-hashes' 'sha256-SHA256("https://example.com/script.js")'; |
| 114 | +<script src="https://example.com/script.js"></script> |
| 115 | +``` |
127 | 116 |
|
128 |
| -### [Tricky design choice #1] |
129 | 117 |
|
130 |
| -[Talk through the tradeoffs in coming to the specific design point you want to make.] |
| 118 | +or |
131 | 119 |
|
132 |
| -```js |
133 |
| -// Illustrated with example code. |
| 120 | + |
| 121 | +``` |
| 122 | +Content-Security-Policy: script-src 'url-hashes' 'sha256-SHA256("script.js")'; |
| 123 | +<script src="script.js"></script> |
134 | 124 | ```
|
135 | 125 |
|
136 |
| -[This may be an open question, |
137 |
| -in which case you should link to any active discussion threads.] |
138 | 126 |
|
139 |
| -### [Tricky design choice 2] |
140 | 127 |
|
141 |
| -[etc.] |
| 128 | +### Extend script hashes to cover eval |
| 129 | + |
| 130 | +Similarly, scripts run within eval() currently can only be allowed via unsafe-eval, which allows any script, with no mechanism to allowlist only specific ones. This proposes that script hashes should cover scripts loaded via eval, in addition to inline scripts, e.g. given a CSP of `script-src 'sha256-SHA256(foo)'; `permitting `eval(foo);` |
| 131 | + |
| 132 | + |
| 133 | +### Add hashes to CSP reporting |
| 134 | + |
| 135 | +In order to facilitate easier adoption, script hashes should also be added to CSP reports. This would permit a developer to set a restrictive [report-only CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only), and use the hashes reported to build out a narrowly-defined hash-based allowlist. |
| 136 | + |
| 137 | +This necessitates adding two fields: the hash of the content of a script (for inline/eval scripts), and the hash of the URL (initial URL, without following redirects) of the script (for script src elements). |
| 138 | + |
| 139 | + |
| 140 | +### **Deployment use case examples** |
| 141 | + |
| 142 | + |
| 143 | +### Single-page applications |
| 144 | + |
| 145 | +To create a hash-based policy for a static, single-page application, the developer can run tooling to parse the HTML of the application and calculate the hashes of all inline <script> blocks, URLs present in <script src> attributes, and code blocks used in eval or New Function() blocks. |
142 | 146 |
|
143 |
| -## Considered alternatives |
| 147 | +The tooling can generate a list of hashes and potentially automatically insert an HTML <meta> tag with their values, e.g. <meta http-equiv="Content-Security-Policy" content="script-src ‘sha256-abc...” url-hashes 'sha256-xyz…'">. The developer can optionally add the 'strict-dynamic' keyword to permit allowlisted scripts to transitively load additional scripts at runtime. |
144 | 148 |
|
145 |
| -[This should include as many alternatives as you can, |
146 |
| -from high level architectural decisions down to alternative naming choices.] |
| 149 | +This could be achieved at compilation time. Any time the application is redeployed, if the scripts have changed, the hashes will be updated to match the new script values. |
147 | 150 |
|
148 |
| -### [Alternative 1] |
149 | 151 |
|
150 |
| -[Describe an alternative which was considered, |
151 |
| -and why you decided against it.] |
| 152 | +### Server-side applications |
152 | 153 |
|
153 |
| -### [Alternative 2] |
| 154 | +To semi-automatically create a strong hash-based policy for an application with a server-side component developers can use the following approach: |
154 | 155 |
|
155 |
| -[etc.] |
156 | 156 |
|
157 |
| -## Stakeholder Feedback / Opposition |
158 | 157 |
|
159 |
| -[Implementors and other stakeholders may already have publicly stated positions on this work. If you can, list them here with links to evidence as appropriate.] |
| 158 | +* Set an application-wide report-only CSP of script-src 'report-hashes' 'report-sample'; report-uri /csp-reports in a production environment. |
| 159 | +* Collect the reported hashes and create a list of all the hashes of scripts executing in the production environment. |
| 160 | +* The developer could optionally investigate the reported hashes (to verify that they correspond to expected application markup) before adding them to the CSP directive and removing report-only. URLs could also be included in the report to facilitate this. |
| 161 | +* Create an enforcing policy listing all the collected hashes. |
160 | 162 |
|
161 |
| -- [Implementor A] : Positive |
162 |
| -- [Stakeholder B] : No signals |
163 |
| -- [Implementor C] : Negative |
| 163 | +This process could also be delegated to a third-party service - the developer would only need to set a reporting CSP header and after a few days/weeks would receive a list of hashes to include in their enforcing CSP. |
164 | 164 |
|
165 |
| -[If appropriate, explain the reasons given by other implementors for their concerns.] |
| 165 | +After the application enforces a hash-based CSP, if a developer adds a new script or modifies an existing one, they will immediately notice that the script is blocked from executing and needs a new hash to be added to the policy to be enabled. |
166 | 166 |
|
167 |
| -## References & acknowledgements |
| 167 | +This carries a significant promise of allowing the deployment of CSP in legacy applications which don't undergo frequent changes, but which might otherwise process sensitive data. |
168 | 168 |
|
169 |
| -[Your design will change and be informed by many people; acknowledge them in an ongoing way! It helps build community and, as we only get by through the contributions of many, is only fair.] |
170 | 169 |
|
171 |
| -[Unless you have a specific reason not to, these should be in alphabetical order.] |
| 170 | +## **Open questions** |
| 171 | + |
| 172 | + |
| 173 | +### Should the new script-src-v2 directive override script-src? |
| 174 | + |
| 175 | +As described in the previous section, this would launch with a new directive so it can be used only on browsers that support the new hashes functionality, while keeping the less strict directives in place to prevent breakage in older browsers that don’t yet support it. This means we have to decide whether the new directive completely replaces script-src in browsers that support it, or whether the browser attempts to enforce both (and prefers the stricter one). The main advantage of completely replacing it is that there is no ambiguity in which directives will be enforced, however it means there is an opportunity for script-src-v2 to be mistakenly configured as less strict than script-src. |
| 176 | + |
| 177 | + |
| 178 | +## **Considered alternatives** |
| 179 | + |
| 180 | + |
| 181 | +### Allowlist external scripts directly by URL, instead of URL hash |
| 182 | + |
| 183 | +The `host-sources` directive allows allowlisting by hostname, but has the following limitations: |
| 184 | + |
| 185 | + |
| 186 | + |
| 187 | +* host-sources does not include anything after the path (e.g. can allowlist /foo/bar.js, but not /jsonp?callback=foo) |
| 188 | +* host-sources follows redirects (i.e. the redirect target needs to also be part of the allowlist), which we do not want for the new directive |
| 189 | +* ‘strict-dynamic’ makes the browser ignore host-sources. |
| 190 | + |
| 191 | +While it would be possible to introduce a new URL-based directive with different semantics (e.g. that includes URL parameters), including a large list of URLs may exceed the response header limit quickly. Some cursory investigation of HTTP Archive data suggests that, for large sites, hashes result in significantly shorter allowlists than do raw URLs. |
| 192 | + |
| 193 | + |
| 194 | +### Overload the existing unsafe-hashes keyword |
| 195 | + |
| 196 | +[unsafe-hashes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy#unsafe-hashes) is an existing directive that allows hashes to apply to event handlers (if not set, hashes currently only apply to inline <script> blocks). It was introduced [[1](https://github.com/w3c/webappsec-csp/issues/13#issuecomment-186708533), [2](https://docs.google.com/document/d/1_nYS4gWYO2Oh8rYDyPglXIKNsgCRVhmjHqWlTAHst7c/edit?tab=t.0#heading=h.h95n37p306j5)] because allowlisting inline scripts for event handlers is considered unsafe even when using hashes, as a script that can be safe when used for a particular event handler (e.g. `<button onclick="transferAllMyMoney()">Transfer all my money</button>`) might not be safe for a different handler (e.g. `<image src="doesnotexist.test" onerror="transferAllMyMoney() />`) or as an inline script. |
| 197 | + |
| 198 | +For simplicity, we could reuse `unsafe-hashes` to have hashes apply to eval and script URLs, however in the eval case, this would mean that scripts would be implicitly allowlisted for event handlers, which is not intended. For this reason we decided not to require unsafe-hashes for eval. This design implicitly allows scripts allowlisted for eval via hashes to also be used in an inline block. This seems fine, but if it’s determined that we do need a keyword to split allowlisting scripts for eval from allowlisting them for inline use, we can add a separate eval-hashes keyword. |
| 199 | + |
| 200 | +We propose using the new url-hashes keyword instead of reusing unsafe-hashes to avoid confusion from using the same directive to allow two different uses (and since allowlisting urls is not, in fact, “unsafe”). |
| 201 | + |
| 202 | + |
| 203 | +### report-hash keyword |
| 204 | + |
| 205 | +There is also [a proposal](https://github.com/w3c/webappsec-csp/pull/693) for reporting hashes of content of all scripts, including script src elements. That proposal aims to audit the content of all scripts running on the page, while the reporting in this proposal aims to facilitate the deployment of this proposal's policy. Reporting also happens at different times in the two proposals (request time or parsing/eval time for this CSP-building proposal, and response time for the other proposal). |
| 206 | + |
| 207 | + |
| 208 | +## **Stakeholder Feedback / Opposition** |
| 209 | + |
| 210 | +No signals yet |
| 211 | + |
| 212 | + |
| 213 | +## **References & acknowledgements** |
172 | 214 |
|
173 | 215 | Many thanks for valuable feedback and advice from:
|
174 | 216 |
|
175 |
| -- [Person 1] |
176 |
| -- [Person 2] |
177 |
| -- [etc.] |
| 217 | + |
| 218 | + |
| 219 | +* Arthur Janc |
| 220 | +* David Dworken |
| 221 | +* Domenic Denicola |
| 222 | +* Lukas Weichselbaum |
| 223 | +* Mike West |
0 commit comments