Fossil SCM

fossil-scm / www / defcsp.md
1
# The Default Content Security Policy (CSP)
2
3
When Fossil’s web interface generates an HTML page, it normally includes
4
a [Content Security Policy][csp] (CSP) in the `<head>`. The CSP specifies
5
allowed sources for external resources such as images,
6
CSS, javascript, and so forth.
7
The purpose of CSP is to provide an extra layer of protection against
8
[cross-site scripting][xss] (XSS) and code injection
9
attacks. Compatible web browsers will not use external resources unless
10
they are specifically allowed by the CSP, which dramatically reduces
11
the attack surface of the application.
12
13
Fossil does not rely on CSP for security.
14
A Fossil server should be secure from attack even without CSP.
15
Fossil includes built-in server-side content filtering logic.
16
For example, Fossil purposely breaks `<script>` tags when it finds
17
them in Markdown and Fossil Wiki documents. And the Fossil build
18
process scans the source code for potential injection vulnerabilities
19
and refuses to compile if any problems are found.
20
However, CSP provides an additional layer of defense against undetected
21
bugs that might lead to a vulnerability.
22
23
## The Default Restrictions
24
25
The default CSP used by Fossil is as follows:
26
27
<pre>
28
default-src 'self' data:;
29
script-src 'self' 'nonce-$nonce';
30
style-src 'self' 'unsafe-inline';
31
img-src * data:;
32
</pre>
33
34
The default is recommended for most installations. However,
35
the site administrators can overwrite this default CSP using the
36
[default-csp setting](/help/default-csp). For example,
37
CSP restrictions can be completely disabled by setting the default-csp to:
38
39
default-src *;
40
41
The following sections detail the maining of the default CSP setting.
42
43
### <a id="base"></a> default-src 'self' data:
44
45
This policy means mixed-origin content isn’t allowed, so you can’t refer
46
to resources on other web domains. Browsers will ignore a link like the
47
one in the following Markdown under our default CSP:
48
49
![fancy 3D Fossil logotype](https://i.imgur.com/HalpMgt.png)
50
51
If you look in the browser’s developer console, you should see a CSP
52
error when attempting to render such a page.
53
54
The default policy does allow inline `data:` URIs, which means you could
55
[data-encode][de] your image content and put it inline within the
56
document:
57
58
![small inline image](data:image/gif;base64,R0lGODlh...)
59
60
That method is best used for fairly small resources. Large `data:` URIs
61
are hard to read and edit. There are secondary problems as well: if you
62
put a large image into a Fossil forum post this way, anyone subscribed
63
to email alerts will get a copy of the raw URI text, which can amount to
64
pages and pages of [ugly Base64-encoded text][b64].
65
66
For inline images within [embedded documentation][ed], it suffices to
67
store the referred-to files in the repo and then refer to them using
68
repo-relative URLs:
69
70
![large inline image](./inlineimage.jpg)
71
72
This avoids bloating the doc text with `data:` URI blobs:
73
74
There are many other cases, [covered below](#serving).
75
76
[b64]: https://en.wikipedia.org/wiki/Base64
77
[svr]: ./server/
78
79
80
### <a id="img"></a> img-src * data:
81
82
It was not always thus, but after careful consideration, we’ve chosen to
83
leave the source of inline images unrestricted by default in Fossil.
84
This allows you to pull them in from remote systems, to pull them from
85
within the Fossil repository itself, or to use `data:` URIs.
86
87
If you are certain all images come from only within the repository, you
88
can close off certain risks — tracking pixels, broken image format
89
decoders, system dialog box spoofing, etc. — by changing this to
90
“`img-src 'self'`” possibly followed by “`data:`” if you will also use
91
`data:` URIs.
92
93
94
### <a id="style"></a> style-src 'self' 'unsafe-inline'
95
96
This policy allows CSS information to come from separate files hosted
97
under the Fossil repo server’s Internet domain. It also allows inline CSS
98
`<style>` tags within the document text.
99
100
The `'unsafe-inline'` declaration allows CSS within individual HTML
101
elements:
102
103
<p style="margin-left: 4em">Indented text.</p>
104
105
As the "`unsafe-`" prefix on the name implies, the `'unsafe-inline'`
106
feature is suboptimal for security. However, there are
107
a few places in the Fossil-generated HTML that benefit from this
108
flexibility and the work-arounds are verbose and difficult to maintain.
109
Furthermore, the harm that can be done with style injections is far
110
less than the harm possible with injected javascript. And so the
111
`'unsafe-inline'` compromise is accepted for now, though it might
112
go away in some future release of Fossil.
113
114
115
### <a id="script"></a> script-src 'self' 'nonce-%s'
116
117
This policy disables in-line JavaScript and only allows `<script>`
118
elements if the `<script>` includes a `nonce` attribute that matches the
119
one declared by the CSP. That nonce is a large random number, unique for
120
each HTTP page generated by Fossil, so an attacker cannot guess the
121
value, so the browser will ignore an attacker’s injected JavaScript.
122
123
That nonce can only come from one of three sources, all of which should
124
be protected at the system administration level on the Fossil server:
125
126
* **Fossil server C code:** All code paths in Fossil that emit
127
`<script>` elements include the `nonce` attribute. There are several
128
cases, such as the “JavaScript” section of a [custom skin][cs].
129
That text is currently inserted into each HTML page generated by
130
Fossil,¹ which means it needs to include a `nonce` attribute to
131
allow it to run under this default CSP. We consider JavaScript
132
emitted via these paths to be safe because it’s audited by the
133
Fossil developers. We assume that you got your Fossil server’s code
134
from a trustworthy source and that an attacker cannot replace your
135
Fossil server binary.
136
137
* **TH1 code:** The Fossil TH1 interpreter pre-defines the
138
[`$nonce` variable](./th1.md#nonce) for use in [custom skins][cs]. For
139
example, some of the stock skins that ship with Fossil include a
140
wall clock feature up in the corner that updates once a minute.
141
These paths are safe in the default Fossil configuration because
142
only the [all-powerful Setup user][su] can write TH1 code that
143
executes in the server’s running context.
144
145
There is, however, [a default-disabled path](#xss) to beware of,
146
covered in the next section.
147
148
* **[CGI server extensions][ext]:** Fossil exports the nonce to the
149
CGI in the `FOSSIL_NONCE` environment variable, which it can then
150
use in `<script>` elements it generates. Because these extensions
151
can only be installed by the Fossil server’s system administrator,
152
this path is also considered safe.
153
154
[ext]: ./serverext.wiki
155
[su]: ./caps/admin-v-setup.md#apsu
156
157
158
#### <a id="xss"></a>Cross-Site Scripting via Ordinary User Capabilities
159
160
We’re so restrictive about how we treat JavaScript because it can lead
161
to difficult-to-avoid scripting attacks. If we used the same CSP for
162
`<script>` tags [as for `<style>` tags](#style), anyone with check-in
163
rights on your repository could add a JavaScript file to your repository
164
and then refer to it from other content added to the site. Since
165
JavaScript code can access any data from any URI served under its same
166
Internet domain, and many Fossil users host multiple Fossil repositories
167
under a single Internet domain, such a CSP would only be safe if all of
168
those repositories are trusted equally.
169
170
Consider [the Chisel hosting service](http://chiselapp.com/), which
171
offers free Fossil repository hosting to anyone on the Internet, all
172
served under the same `http://chiselapp.com/user/$NAME/$REPO` URL
173
scheme. Any one of those hundreds of repositories could trick you into
174
visiting their repository home page, set to [an HTML-formatted embedded
175
doc page][hfed] via Admin → Configuration → Index&nbsp;Page, with this
176
content:
177
178
<script src="/doc/trunk/bad.js"></script>
179
180
That script can then do anything allowed in JavaScript to *any other*
181
Chisel repository your browser can access. The possibilities for mischief
182
are *vast*. For just one example, if you have login cookies on four
183
different Chisel repositories, your attacker could harvest the login
184
cookies for all of them through this path if we allowed Fossil to serve
185
JavaScript files under the same CSP policy as we do for CSS files.
186
187
This is why the default configuration of Fossil has no way for [embedded
188
docs][ed], [wiki articles][wiki], [tickets][tkt], [forum posts][fp], or
189
[tech notes][tn] to automatically insert a nonce into the page content.
190
This is all user-provided content, which could link to user-provided
191
JavaScript via check-in rights, effectively giving all such users a
192
capability that is usually reserved to the repository’s administrator.
193
194
The default-disabled [TH1 documents feature][edtf] is the only known
195
path around this restriction. If you are serving a Fossil repository
196
that has any user you do not implicitly trust to a level that you would
197
willingly run any JavaScript code they’ve provided, blind, you **must
198
not** give the `--with-th1-docs` option when configuring Fossil, because
199
that allows substitution of the [pre-defined `$nonce` TH1
200
variable](./th1.md#nonce) into [HTML-formatted embedded docs][hfed]:
201
202
<script src="/doc/trunk/bad.js" nonce="$nonce"></script>
203
204
Even with this feature enabled, you cannot put `<script>` tags into
205
Fossil Wiki or Markdown-formatted content, because our HTML generators
206
for those formats purposely strip or disable such tags in the output.
207
Therefore, if you trust those users with check-in rights to provide
208
JavaScript but not those allowed to file tickets, append to wiki
209
articles, etc., you might justify enabling TH1 docs on your repository,
210
since the only way to create or modify HTML-formatted embedded docs is
211
through check-ins.
212
213
[ed]: ./embeddeddoc.wiki
214
[edtf]: ./embeddeddoc.wiki#th1
215
[hfed]: ./embeddeddoc.wiki#html
216
217
218
## <a id="serving"></a>Serving Files Within the Limits
219
220
There are several ways to serve files within the above restrictions,
221
avoiding the need to [override the default CSP](#override). In
222
decreasing order of simplicity and preference:
223
224
1. Within [embedded documentation][ed] (only!) you can refer to files
225
stored in the repo using document-relative file URLs:
226
227
![inline image](./inlineimage.jpg)
228
229
2. Relative file URLs don’t work from [wiki articles][wiki],
230
[tickets][tkt], [forum posts][fp], or [tech notes][tn], but you can
231
still refer to them inside the repo with [`/doc`][du] or
232
[`/raw`][ru] URLs:
233
234
![inline image](/doc/trunk/images/inlineimage.jpg)
235
<img src="/raw/logo.png" style="float: right; margin-left: 2em">
236
237
3. Store the files as [unversioned content][uv], referred to using
238
[`/uv`][uu] URLs instead:
239
240
![logo](/uv/logo.png)
241
242
4. Use the [optional CGI server extensions feature](./serverext.wiki)
243
to serve such content via `/ext` URLs.
244
245
5. Put Fossil behind a [front-end proxy server][svr] as a virtual
246
subdirectory within the site, so that our default CSP’s “self” rules
247
match static file routes on that same site. For instance, your repo
248
might be at `https://example.com/code`, allowing documents in that
249
repo to refer to:
250
251
* images as `/image/foo.png`
252
* JavaScript files as `/js/bar.js`
253
* CSS style sheets as `/style/qux.css`
254
255
Although those files are all outside the Fossil repo at `/code`,
256
keep in mind that it is the browser’s notion of “self” that matters
257
here, not Fossil’s. All resources come from the same Internet
258
domain, so the browser cannot distinguish Fossil-provided content
259
from static content served directly by the proxy server.
260
261
This method opens up many other potential benefits, such as
262
[TLS encryption][tls], high-performance tuning via custom HTTP
263
headers, integration with other web technologies like PHP, etc.
264
265
You might wonder why we rank in-repo content as most preferred above. It
266
is because the first two options are the only ones that cause such
267
resources to be included in an initial clone or in subsequent repo
268
syncs. The methods further down the list have a number of undesirable
269
properties:
270
271
1. Relative links to out-of-repo files break in `fossil ui` when run on
272
a clone.
273
274
2. Absolute links back to the public repo instance solve that:
275
276
![inline image](https://example.com/images/logo.png)
277
278
...but using them breaks some types of failover and load-balancing
279
schemes, because it creates a [single point of failure][spof].
280
281
3. Absolute links fail when one’s purpose in using a clone is to
282
recover from the loss of a project web site by standing that clone
283
up [as a server][svr] elsewhere. You probably forgot to copy such
284
external resources in the backup copies, so that when the main repo
285
site disappears, so do those files.
286
287
Unversioned content is in the middle of the first list above — between
288
fully-external content and fully in-repo content — because it isn’t
289
included in a clone unless you give the `--unversioned` flag. If you
290
then want updates to the unversioned content to be included in syncs,
291
you have to give the same flag to [a `sync` command](/help/sync).
292
There is no equivalent with other commands such as `up` and `pull`, so
293
you must then remember to give `fossil uv` commands when necessary to
294
pull new unversioned content down.
295
296
Thus our recommendation that you refer to in-repo resources exclusively.
297
298
[du]: /help/www/doc
299
[fp]: ./forum.wiki
300
[ru]: /help/www/raw
301
[spof]: https://en.wikipedia.org/wiki/Single_point_of_failure
302
[tkt]: ./tickets.wiki
303
[tn]: ./event.wiki
304
[tls]: ./server/debian/nginx.md
305
[uu]: /help/www/uv
306
[uv]: ./unvers.wiki
307
[wiki]: ./wikitheory.wiki
308
309
310
## <a id="override"></a>Overriding the Default CSP
311
312
If you wish to relax the default CSP’s restrictions or to tighten them
313
further, there are multiple ways to accomplish that.
314
315
The following methods are listed in top-down order to give the simplest
316
and most straightforward method first. Further methods dig down deeper
317
into the stack, which is helpful to understand even if you end up using
318
a higher-level method.
319
320
321
### <a id="cspsetting"></a>The `default-csp` Setting
322
323
If the [`default-csp` setting](/help/default-csp) is defined and is
324
not an empty string, its value is injected into the page using
325
[TH1](./th1.md) via one or more of the methods below, depending on the
326
skin you’re using and local configuration.
327
328
Changing this setting is the easiest way to set a nonstandard CSP on
329
your site.
330
331
Because a blank setting tells Fossil to use its hard-coded default CSP,
332
you have to say something like the following to get a repository without
333
content security policy restrictions:
334
335
$ fossil set -R /path/to/served/repo.fossil default-csp 'default-src *'
336
337
We recommend that instead of using the command line to change this
338
setting that you do it via the repository’s web interface, in
339
Admin → Settings. Write your CSP rules in the edit box marked
340
"`default-csp`". Do not add hard newlines in that box: the setting needs
341
to be on a single long line. Beware that changes take effect
342
immediately, so be careful with your edits: you could end up locking
343
yourself out of the repository with certain CSP changes!
344
345
There are a few reasons why changing this setting via the command line
346
is inadvisable, except for very short settings like the example above:
347
348
1. You have to be sure to set it on the repository where you want the
349
CSP to apply. Changing this setting on your local clone doesn’t
350
affect the remote repo you cloned from, which is most likely where
351
you want the CSP restrictions.
352
353
2. For more complicated CSPs, the quoting rules for your shell and the
354
CSP syntax may interact, making it difficult or impossible to set
355
your desired CSP via the command line. Setting it via the web UI
356
doesn’t have this problem.
357
358
359
360
### <a id="th1"></a>TH1 Setup Hook
361
362
Fossil sets [the TH1 variable `$default_csp`][thvar] from the
363
`default-csp` setting and uses *that* to inject the value into generated
364
HTML pages in its stock configuration.
365
366
This means that another way you can override this value is to use
367
the [`th1-setup` hook script](./th1-hooks.md), which runs before TH1
368
processing happens during skin processing:
369
370
$ fossil set th1-setup "set default_csp {default-src 'self'}"
371
372
After [the above](#admin-ui), this is the cleanest method.
373
374
[thvar]: ./customskin.md#vars
375
376
377
378
### <a id="csrc"></a>Fossil C Source Code
379
380
When you do neither of the above things, Fossil uses
381
[a hard-coded default](/info?ln=527-530&name=65a555d0d4fb846b).
382
383
We tell you about this not to suggest that you hack the Fossil C source
384
code to change the CSP but simply to document the next step before we
385
move down-stack.
386
387
388
389
### <a id="header"></a>Skin Header
390
391
[In the normal case](./customskin.md#override), Fossil injects the CSP
392
retrieved by one of the above methods into the header of all HTML
393
documents it generates:
394
395
```HTML
396
<head>...
397
<meta http-equiv="Content-Security-Policy" content="...">
398
...
399
```
400
401
Fossil skips this when you’re using a custom skin *and* its
402
[Header section](./customskin.md#headfoot) includes a `<body>` tag. This
403
is because prior to Fossil 2.5, the Header for a custom skin normally
404
contained everything from the opening `<html>` tag through the leading
405
`<body>` tag. From that version onward, Fossil now generates that header
406
when possible, so that the skin’s Header normally provides only the
407
opening tags of the document body, rather than the HTML header.
408
409
When we added CSP support in Fossil 2.7, we made use of that mechanism
410
to inject the CSP into the generated HTML document header.
411
412
For backwards compatibility, Fossil skips this when the skin’s Header
413
includes a `<body>` tag. Fossil takes that as a hint that it’s dealing
414
with a skin made in the pre-Fossil-2.5 days and doesn’t try to blindly
415
override it.
416
417
The problem then is that you may be a Fossil user from the days before
418
Fossil 2.5, and you may be using a custom skin. This includes users who
419
selected one of the stock skins, since for the purposes of this section,
420
there is no difference between the cases. If you go into Admin → Skins →
421
Header and find a `<body>` tag, none of the above will apply to your
422
repo since Fossil will not be injecting its CSP into your pages.
423
424
If you selected one of the stock skins (e.g. Khaki) prior to upgrading
425
to Fossil 2.5+ and didn’t make any changes to it since that time, you
426
can take the simplest option, which is to simply revert to the stock
427
version of the skin, so your pages will have the CSP injected, at which
428
point this document will begin describing what Fossil does with that
429
repo.
430
431
If you’re using a customized version of one of the stock skins, the
432
skinning mechanism has a diff feature to make it easier to fold your
433
local changes into the stock version.
434
435
If you’re using a fully customized skin, we recommend replicating the
436
method that [the Bootstrap skin uses][dcinj].² Alone among the stock
437
Fossil skins, Bootstrap still does old-style Header processing,
438
providing the entire HTML header and the start of the document body.
439
440
We do *not* recommend injecting an explicit `Content-Security-Policy`
441
meta tag into a header to override Fossil’s default CSP. That means you
442
have to edit the skin every time you want to change the CSP. Use the TH1
443
`$default_csp` variable like the Bootstrap skin does so you can use one
444
of the methods above with your custom skin, so the CSP can vary
445
independently of the skin.
446
447
[dcinj]: /info?ln=7&name=bef080a6929a3e6f
448
449
450
### <a id="fep"></a>Front-End Proxy
451
452
If your Fossil repo is behind some sort of HTTP [front-end proxy][svr],
453
the [preferred method][pmcsp] for setting the CSP is via a custom HTTP
454
header, which most HTTP reverse proxy programs allow.
455
456
Beware that if you have a CSP set via both the HTTP and HTML headers
457
that the two CSPs [merge](https://stackoverflow.com/a/51153816/142454),
458
taking the most restrictive elements of each CSP. If you wish the proxy
459
layer’s setting to completely override Fossil’s setting, you will need
460
to combine that with one of the methods above to either remove the
461
Fossil-provided CSP or to make Fossil provide a no-restrictions CSP
462
which the front-end proxy can then tighten down.
463
464
[pmcsp]: https://developers.google.com/web/fundamentals/security/csp/#the_meta_tag
465
466
467
468
------------
469
470
471
**Asides and Digressions:**
472
473
1. Fossil might someday switch to serving the “JavaScript” section of a
474
custom skin as a virtual text file, allowing it to be cached by the
475
browser, reducing page load times.
476
477
2. The stock Bootstrap skin *did* provide redundant CSP text from
478
Fossil 2.7 through Fossil 2.9, so setting the CSP via the higher
479
level methods did not work with that skin. We fixed this in Fossil
480
2.10, but if you selected the Bootstrap skin prior to that, you’re
481
now running on a *copy* of it stored in your repo settings table, so
482
the change to the stock version of the skin won’t affect that repo
483
automatically. You will have to either merge the diffs in with your
484
local changes or revert to the stock version of the skin.
485
486
487
[cs]: ./customskin.md
488
[csp]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
489
[de]: https://dopiaza.org/tools/datauri/index.php
490
[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting
491

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button