Fossil SCM
More thorough explanation of <script nonce> in www/defcsp.md, and explained the reason why Fossil has no way of providing that nonce in most content types rather than link to the "XSS via check-in rights" forum post. This new presentation of that post's ideas is more detailed and includes discussion of the feature's interaction with the TH1 docs feature.
Commit
8d43bb8786772d5737012216aa58982865cfa749d35ba2325a4ccf114ac01a2c
Parent
366b23a180f7734…
2 files changed
+79
-12
+2
-2
+79
-12
| --- www/defcsp.md | ||
| +++ www/defcsp.md | ||
| @@ -89,22 +89,86 @@ | ||
| 89 | 89 | |
| 90 | 90 | ### <a name="script"></a> script-src 'self' 'nonce-%s' |
| 91 | 91 | |
| 92 | 92 | This policy means HTML `<script>` tags are only allowed to be emitted |
| 93 | 93 | into the output HTML by Fossil C or TH1 code, because only code running |
| 94 | -in those contexts can correctly apply the random “nonce” attribute to | |
| 95 | -the tag that matches the one declared in the CSP, which changes on each | |
| 96 | -HTTP hit Fossil handles. | |
| 97 | - | |
| 98 | -This means the workarounds given above will not work for JavaScript. In | |
| 99 | -effect, the only JavaScript that Fossil can serve is that which it | |
| 100 | -directly provided, such as that for the CSS section of the skin and that | |
| 101 | -behind the default [hamburger menu](./customskin.md#menu). | |
| 94 | +in those contexts can insert the correct “nonce” tag attribute, matching | |
| 95 | +the one declared in the CSP.¹ Since the nonce is a very large random | |
| 96 | +number that changes on each HTTP hit Fossil handles, it is effectively | |
| 97 | +unguessable, which prevents attackers from inserting `<script>` tags | |
| 98 | +statically. | |
| 99 | + | |
| 100 | +This means the workarounds given above will not work for JavaScript. | |
| 101 | +Under this policy, the only JavaScript that Fossil can serve is that | |
| 102 | +which it directly provided. | |
| 103 | + | |
| 104 | +Users with the all-powerful Setup capability can insert arbitrary | |
| 105 | +JavaScript by [defining a custom skin][cs], adding it to the skin’s | |
| 106 | +“JavaScript” section, which has the random nonce automatically inserted | |
| 107 | +by Fossil when it serves the page. This is how the JS backing the | |
| 108 | +default skin’s [hamburger menu](./customskin.md#menu) works. | |
| 102 | 109 | |
| 103 | 110 | We’re so restrictive about how we treat JavaScript because it can lead |
| 104 | -to [difficult-to-avoid cross-site scripting attacks][xssci]. | |
| 111 | +to difficult-to-avoid scripting attacks. If we used the same CSP for | |
| 112 | +`<script>` tags [as for `<style>` tags](#style), anyone with check-in | |
| 113 | +rights on your repository could add a JavaScript file to your repository | |
| 114 | +and then refer to it from other content added to the site. Since | |
| 115 | +JavaScript code can access any data from any URI served under its same | |
| 116 | +Internet domain, and many Fossil users host multiple Fossil repositories | |
| 117 | +under a single Internet domain, such a CSP would only be safe if all of | |
| 118 | +those repositories are trusted equally. | |
| 119 | + | |
| 120 | +Consider [the Chisel hosting service](http://chiselapp.com/), which | |
| 121 | +offers free Fossil repository hosting to anyone on the Internet, all | |
| 122 | +served under the same `http://chiselapp.com/user/$NAME/$REPO` URL | |
| 123 | +scheme. Any one of those hundreds of repositories could trick you into | |
| 124 | +visiting their repository home page, set to [an HTML-formatted embedded | |
| 125 | +doc page][hfed] via Admin → Configuration → Index Page, with this | |
| 126 | +content: | |
| 127 | + | |
| 128 | + <script src="/doc/trunk/bad.js"></script> | |
| 129 | + | |
| 130 | +That script can then do anything allowed in JavaScript to *any other* | |
| 131 | +Chisel repository your browser can access.The possibilities for mischief | |
| 132 | +are *vast*. For just one example, if you have login cookies on four | |
| 133 | +different Chisel repositories, your attacker could harvest the login | |
| 134 | +cookies for all of them through this path if we allowed Fossil to serve | |
| 135 | +JavaScript files under the same CSP policy as we do for CSS files. | |
| 136 | + | |
| 137 | +This is why the default configuration of Fossil has no way for [embedded | |
| 138 | +docs][ed], [wiki articles][wiki], [tickets][tkt], [forum posts][fp], or | |
| 139 | +[tech notes][tn] to automatically insert a nonce into the page content. | |
| 140 | +This is all user-provided content, which could link to user-provided | |
| 141 | +JavaScript via check-in rights, effectively giving all such users a | |
| 142 | +capability that is usually reserved to the repository’s administrator. | |
| 143 | + | |
| 144 | +The default-disabled [TH1 documents feature][edtf] is the only known | |
| 145 | +path around this restriction. If you are serving a Fossil repository | |
| 146 | +that has any user you do not implicitly trust to a level that you would | |
| 147 | +willingly run any JavaScript code they’ve provided, blind, you **must | |
| 148 | +not** give the `--with-th1-docs` option when configuring Fossil, because | |
| 149 | +that allows substitution of the [pre-defined `$nonce` TH1 | |
| 150 | +variable](./th1.md#nonce) into [HTML-formatted embedded docs][hfed]: | |
| 151 | + | |
| 152 | + <script src="/doc/trunk/bad.js" nonce="$nonce"></script> | |
| 153 | + | |
| 154 | +Even with this feature enabled, you cannot put `<script>` tags into | |
| 155 | +Fossil Wiki or Markdown-formatted content, because our HTML generators | |
| 156 | +for those formats purposely strip or disable such tags in the output. | |
| 157 | +Therefore, if you trust those users with check-in rights to provide | |
| 158 | +JavaScript but not those allowed to file tickets, append to wiki | |
| 159 | +articles, etc., you might justify enabling TH1 docs on your repository, | |
| 160 | +since the only way to create or modify HTML-formatted embedded docs is | |
| 161 | +through check-ins. | |
| 105 | 162 | |
| 163 | +[ed]: ./embeddeddoc.wiki | |
| 164 | +[edtf]: ./embeddeddoc.wiki#th1 | |
| 165 | +[fp]: ./forum.wiki | |
| 166 | +[hfed]: ./embeddeddoc.wiki#html | |
| 167 | +[tkt]: ./tickets.wiki | |
| 168 | +[tn]: ./event.wiki | |
| 169 | +[wiki]: ./wikitheory.wiki | |
| 106 | 170 | |
| 107 | 171 | |
| 108 | 172 | ## <a name="override"></a>Replacing the Default CSP |
| 109 | 173 | |
| 110 | 174 | If you wish to relax the default CSP’s restrictions or to tighten them |
| @@ -137,11 +201,11 @@ | ||
| 137 | 201 | |
| 138 | 202 | ### <a name="header"></a>Custom Skin Header |
| 139 | 203 | |
| 140 | 204 | Fossil only inserts a CSP into the HTML pages it generates when the |
| 141 | 205 | [skin’s Header section](./customskin.md#headfoot) doesn’t contain a |
| 142 | -`<head>` tag. None of the stock skins include a `<head>` tag,¹ so if you | |
| 206 | +`<head>` tag. None of the stock skins include a `<head>` tag,² so if you | |
| 143 | 207 | haven’t [created a custom skin][cs], you should be getting Fossil’s |
| 144 | 208 | default CSP. |
| 145 | 209 | |
| 146 | 210 | We say “should” because long-time Fossil users may be hanging onto a |
| 147 | 211 | legacy behavior from before Fossil 2.5, when Fossil added this automatic |
| @@ -172,16 +236,19 @@ | ||
| 172 | 236 | ------------ |
| 173 | 237 | |
| 174 | 238 | |
| 175 | 239 | **Asides and Digressions:** |
| 176 | 240 | |
| 177 | -1. The stock Bootstrap skin does actually include a `<head>` tag, but | |
| 241 | +1. There is actually a third context that can correctly insert this | |
| 242 | + nonce attribute: [a CGI server extension](./serverext.wiki), by use of | |
| 243 | + the `FOSSIL_NONCE` variable sent to the CGI by Fossil. | |
| 244 | + | |
| 245 | +2. The stock Bootstrap skin does actually include a `<head>` tag, but | |
| 178 | 246 | from Fossil 2.7 through Fossil 2.9, it just repeated the same CSP |
| 179 | 247 | text that Fossil’s C code inserts into the HTML header for all other |
| 180 | 248 | stock skins. With Fossil 2.10, the stock Bootstrap skin uses |
| 181 | 249 | `$default_csp` instead, so you can [override it as above](#th1). |
| 182 | 250 | |
| 183 | 251 | |
| 184 | 252 | [cs]: ./customskin.md |
| 185 | 253 | [csp]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP |
| 186 | 254 | [de]: https://dopiaza.org/tools/datauri/index.php |
| 187 | -[xssci]: https://fossil-scm.org/forum/forumpost/e7c386b21f | |
| 188 | 255 |
| --- www/defcsp.md | |
| +++ www/defcsp.md | |
| @@ -89,22 +89,86 @@ | |
| 89 | |
| 90 | ### <a name="script"></a> script-src 'self' 'nonce-%s' |
| 91 | |
| 92 | This policy means HTML `<script>` tags are only allowed to be emitted |
| 93 | into the output HTML by Fossil C or TH1 code, because only code running |
| 94 | in those contexts can correctly apply the random “nonce” attribute to |
| 95 | the tag that matches the one declared in the CSP, which changes on each |
| 96 | HTTP hit Fossil handles. |
| 97 | |
| 98 | This means the workarounds given above will not work for JavaScript. In |
| 99 | effect, the only JavaScript that Fossil can serve is that which it |
| 100 | directly provided, such as that for the CSS section of the skin and that |
| 101 | behind the default [hamburger menu](./customskin.md#menu). |
| 102 | |
| 103 | We’re so restrictive about how we treat JavaScript because it can lead |
| 104 | to [difficult-to-avoid cross-site scripting attacks][xssci]. |
| 105 | |
| 106 | |
| 107 | |
| 108 | ## <a name="override"></a>Replacing the Default CSP |
| 109 | |
| 110 | If you wish to relax the default CSP’s restrictions or to tighten them |
| @@ -137,11 +201,11 @@ | |
| 137 | |
| 138 | ### <a name="header"></a>Custom Skin Header |
| 139 | |
| 140 | Fossil only inserts a CSP into the HTML pages it generates when the |
| 141 | [skin’s Header section](./customskin.md#headfoot) doesn’t contain a |
| 142 | `<head>` tag. None of the stock skins include a `<head>` tag,¹ so if you |
| 143 | haven’t [created a custom skin][cs], you should be getting Fossil’s |
| 144 | default CSP. |
| 145 | |
| 146 | We say “should” because long-time Fossil users may be hanging onto a |
| 147 | legacy behavior from before Fossil 2.5, when Fossil added this automatic |
| @@ -172,16 +236,19 @@ | |
| 172 | ------------ |
| 173 | |
| 174 | |
| 175 | **Asides and Digressions:** |
| 176 | |
| 177 | 1. The stock Bootstrap skin does actually include a `<head>` tag, but |
| 178 | from Fossil 2.7 through Fossil 2.9, it just repeated the same CSP |
| 179 | text that Fossil’s C code inserts into the HTML header for all other |
| 180 | stock skins. With Fossil 2.10, the stock Bootstrap skin uses |
| 181 | `$default_csp` instead, so you can [override it as above](#th1). |
| 182 | |
| 183 | |
| 184 | [cs]: ./customskin.md |
| 185 | [csp]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP |
| 186 | [de]: https://dopiaza.org/tools/datauri/index.php |
| 187 | [xssci]: https://fossil-scm.org/forum/forumpost/e7c386b21f |
| 188 |
| --- www/defcsp.md | |
| +++ www/defcsp.md | |
| @@ -89,22 +89,86 @@ | |
| 89 | |
| 90 | ### <a name="script"></a> script-src 'self' 'nonce-%s' |
| 91 | |
| 92 | This policy means HTML `<script>` tags are only allowed to be emitted |
| 93 | into the output HTML by Fossil C or TH1 code, because only code running |
| 94 | in those contexts can insert the correct “nonce” tag attribute, matching |
| 95 | the one declared in the CSP.¹ Since the nonce is a very large random |
| 96 | number that changes on each HTTP hit Fossil handles, it is effectively |
| 97 | unguessable, which prevents attackers from inserting `<script>` tags |
| 98 | statically. |
| 99 | |
| 100 | This means the workarounds given above will not work for JavaScript. |
| 101 | Under this policy, the only JavaScript that Fossil can serve is that |
| 102 | which it directly provided. |
| 103 | |
| 104 | Users with the all-powerful Setup capability can insert arbitrary |
| 105 | JavaScript by [defining a custom skin][cs], adding it to the skin’s |
| 106 | “JavaScript” section, which has the random nonce automatically inserted |
| 107 | by Fossil when it serves the page. This is how the JS backing the |
| 108 | default skin’s [hamburger menu](./customskin.md#menu) works. |
| 109 | |
| 110 | We’re so restrictive about how we treat JavaScript because it can lead |
| 111 | to difficult-to-avoid scripting attacks. If we used the same CSP for |
| 112 | `<script>` tags [as for `<style>` tags](#style), anyone with check-in |
| 113 | rights on your repository could add a JavaScript file to your repository |
| 114 | and then refer to it from other content added to the site. Since |
| 115 | JavaScript code can access any data from any URI served under its same |
| 116 | Internet domain, and many Fossil users host multiple Fossil repositories |
| 117 | under a single Internet domain, such a CSP would only be safe if all of |
| 118 | those repositories are trusted equally. |
| 119 | |
| 120 | Consider [the Chisel hosting service](http://chiselapp.com/), which |
| 121 | offers free Fossil repository hosting to anyone on the Internet, all |
| 122 | served under the same `http://chiselapp.com/user/$NAME/$REPO` URL |
| 123 | scheme. Any one of those hundreds of repositories could trick you into |
| 124 | visiting their repository home page, set to [an HTML-formatted embedded |
| 125 | doc page][hfed] via Admin → Configuration → Index Page, with this |
| 126 | content: |
| 127 | |
| 128 | <script src="/doc/trunk/bad.js"></script> |
| 129 | |
| 130 | That script can then do anything allowed in JavaScript to *any other* |
| 131 | Chisel repository your browser can access.The possibilities for mischief |
| 132 | are *vast*. For just one example, if you have login cookies on four |
| 133 | different Chisel repositories, your attacker could harvest the login |
| 134 | cookies for all of them through this path if we allowed Fossil to serve |
| 135 | JavaScript files under the same CSP policy as we do for CSS files. |
| 136 | |
| 137 | This is why the default configuration of Fossil has no way for [embedded |
| 138 | docs][ed], [wiki articles][wiki], [tickets][tkt], [forum posts][fp], or |
| 139 | [tech notes][tn] to automatically insert a nonce into the page content. |
| 140 | This is all user-provided content, which could link to user-provided |
| 141 | JavaScript via check-in rights, effectively giving all such users a |
| 142 | capability that is usually reserved to the repository’s administrator. |
| 143 | |
| 144 | The default-disabled [TH1 documents feature][edtf] is the only known |
| 145 | path around this restriction. If you are serving a Fossil repository |
| 146 | that has any user you do not implicitly trust to a level that you would |
| 147 | willingly run any JavaScript code they’ve provided, blind, you **must |
| 148 | not** give the `--with-th1-docs` option when configuring Fossil, because |
| 149 | that allows substitution of the [pre-defined `$nonce` TH1 |
| 150 | variable](./th1.md#nonce) into [HTML-formatted embedded docs][hfed]: |
| 151 | |
| 152 | <script src="/doc/trunk/bad.js" nonce="$nonce"></script> |
| 153 | |
| 154 | Even with this feature enabled, you cannot put `<script>` tags into |
| 155 | Fossil Wiki or Markdown-formatted content, because our HTML generators |
| 156 | for those formats purposely strip or disable such tags in the output. |
| 157 | Therefore, if you trust those users with check-in rights to provide |
| 158 | JavaScript but not those allowed to file tickets, append to wiki |
| 159 | articles, etc., you might justify enabling TH1 docs on your repository, |
| 160 | since the only way to create or modify HTML-formatted embedded docs is |
| 161 | through check-ins. |
| 162 | |
| 163 | [ed]: ./embeddeddoc.wiki |
| 164 | [edtf]: ./embeddeddoc.wiki#th1 |
| 165 | [fp]: ./forum.wiki |
| 166 | [hfed]: ./embeddeddoc.wiki#html |
| 167 | [tkt]: ./tickets.wiki |
| 168 | [tn]: ./event.wiki |
| 169 | [wiki]: ./wikitheory.wiki |
| 170 | |
| 171 | |
| 172 | ## <a name="override"></a>Replacing the Default CSP |
| 173 | |
| 174 | If you wish to relax the default CSP’s restrictions or to tighten them |
| @@ -137,11 +201,11 @@ | |
| 201 | |
| 202 | ### <a name="header"></a>Custom Skin Header |
| 203 | |
| 204 | Fossil only inserts a CSP into the HTML pages it generates when the |
| 205 | [skin’s Header section](./customskin.md#headfoot) doesn’t contain a |
| 206 | `<head>` tag. None of the stock skins include a `<head>` tag,² so if you |
| 207 | haven’t [created a custom skin][cs], you should be getting Fossil’s |
| 208 | default CSP. |
| 209 | |
| 210 | We say “should” because long-time Fossil users may be hanging onto a |
| 211 | legacy behavior from before Fossil 2.5, when Fossil added this automatic |
| @@ -172,16 +236,19 @@ | |
| 236 | ------------ |
| 237 | |
| 238 | |
| 239 | **Asides and Digressions:** |
| 240 | |
| 241 | 1. There is actually a third context that can correctly insert this |
| 242 | nonce attribute: [a CGI server extension](./serverext.wiki), by use of |
| 243 | the `FOSSIL_NONCE` variable sent to the CGI by Fossil. |
| 244 | |
| 245 | 2. The stock Bootstrap skin does actually include a `<head>` tag, but |
| 246 | from Fossil 2.7 through Fossil 2.9, it just repeated the same CSP |
| 247 | text that Fossil’s C code inserts into the HTML header for all other |
| 248 | stock skins. With Fossil 2.10, the stock Bootstrap skin uses |
| 249 | `$default_csp` instead, so you can [override it as above](#th1). |
| 250 | |
| 251 | |
| 252 | [cs]: ./customskin.md |
| 253 | [csp]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP |
| 254 | [de]: https://dopiaza.org/tools/datauri/index.php |
| 255 |
+2
-2
| --- www/embeddeddoc.wiki | ||
| +++ www/embeddeddoc.wiki | ||
| @@ -80,11 +80,11 @@ | ||
| 80 | 80 | Wiki, markdown, and plain text documentation files |
| 81 | 81 | are rendered with the standard fossil header and footer added. |
| 82 | 82 | Most other mimetypes are delivered directly to the requesting |
| 83 | 83 | web browser without interpretation, additions, or changes. |
| 84 | 84 | |
| 85 | -Files with the mimetype "text/html" (the .html or .htm suffix) are | |
| 85 | +<a name="html"></a>Files with the mimetype "text/html" (the .html or .htm suffix) are | |
| 86 | 86 | usually rendered directly to the browser without interpretation. |
| 87 | 87 | However, if the file begins with a <div> element like this: |
| 88 | 88 | |
| 89 | 89 | <b><div class='fossil-doc' data-title='<i>Title Text</i>'></b> |
| 90 | 90 | |
| @@ -131,11 +131,11 @@ | ||
| 131 | 131 | As you can see, this happens for all source document types that end up |
| 132 | 132 | rendering as HTML, not just source documents in the HTML |
| 133 | 133 | <tt>fossil-doc</tt> format described at the end of the prior section. |
| 134 | 134 | |
| 135 | 135 | |
| 136 | -<h3>2. TH1 Documents</h3> | |
| 136 | +<h3 id="th1">2. TH1 Documents</h3> | |
| 137 | 137 | |
| 138 | 138 | Fossil will substitute the value of [./th1.md | TH1 expressions] within |
| 139 | 139 | <tt>{</tt> curly braces <tt>}</tt> into the output HTML if you have |
| 140 | 140 | configured it with the <tt>--with-th1-docs</tt> option, which is |
| 141 | 141 | disabled by default. |
| 142 | 142 |
| --- www/embeddeddoc.wiki | |
| +++ www/embeddeddoc.wiki | |
| @@ -80,11 +80,11 @@ | |
| 80 | Wiki, markdown, and plain text documentation files |
| 81 | are rendered with the standard fossil header and footer added. |
| 82 | Most other mimetypes are delivered directly to the requesting |
| 83 | web browser without interpretation, additions, or changes. |
| 84 | |
| 85 | Files with the mimetype "text/html" (the .html or .htm suffix) are |
| 86 | usually rendered directly to the browser without interpretation. |
| 87 | However, if the file begins with a <div> element like this: |
| 88 | |
| 89 | <b><div class='fossil-doc' data-title='<i>Title Text</i>'></b> |
| 90 | |
| @@ -131,11 +131,11 @@ | |
| 131 | As you can see, this happens for all source document types that end up |
| 132 | rendering as HTML, not just source documents in the HTML |
| 133 | <tt>fossil-doc</tt> format described at the end of the prior section. |
| 134 | |
| 135 | |
| 136 | <h3>2. TH1 Documents</h3> |
| 137 | |
| 138 | Fossil will substitute the value of [./th1.md | TH1 expressions] within |
| 139 | <tt>{</tt> curly braces <tt>}</tt> into the output HTML if you have |
| 140 | configured it with the <tt>--with-th1-docs</tt> option, which is |
| 141 | disabled by default. |
| 142 |
| --- www/embeddeddoc.wiki | |
| +++ www/embeddeddoc.wiki | |
| @@ -80,11 +80,11 @@ | |
| 80 | Wiki, markdown, and plain text documentation files |
| 81 | are rendered with the standard fossil header and footer added. |
| 82 | Most other mimetypes are delivered directly to the requesting |
| 83 | web browser without interpretation, additions, or changes. |
| 84 | |
| 85 | <a name="html"></a>Files with the mimetype "text/html" (the .html or .htm suffix) are |
| 86 | usually rendered directly to the browser without interpretation. |
| 87 | However, if the file begins with a <div> element like this: |
| 88 | |
| 89 | <b><div class='fossil-doc' data-title='<i>Title Text</i>'></b> |
| 90 | |
| @@ -131,11 +131,11 @@ | |
| 131 | As you can see, this happens for all source document types that end up |
| 132 | rendering as HTML, not just source documents in the HTML |
| 133 | <tt>fossil-doc</tt> format described at the end of the prior section. |
| 134 | |
| 135 | |
| 136 | <h3 id="th1">2. TH1 Documents</h3> |
| 137 | |
| 138 | Fossil will substitute the value of [./th1.md | TH1 expressions] within |
| 139 | <tt>{</tt> curly braces <tt>}</tt> into the output HTML if you have |
| 140 | configured it with the <tt>--with-th1-docs</tt> option, which is |
| 141 | disabled by default. |
| 142 |