The standard browse template uses inline JavaScript and CSS. Chrome has started to warn against this unless a Content Security Policy is set to unsafe-inline, nonce or hash. Using script-src 'self' is no longer accepted. Content Security Policy | Privacy & Security | Chrome for Developers
My question is what would be the best method to solve this? Is using unsafe-inline a real threat vector if the site is HTTPS only?
We could also use a nonce or hash. In this case we need to use a variable in the template, and set the variable value in the Caddyfile. The corresponding CSP header must share the same value. Hardcoding a nonce or hash could be feasible in my personal setup, though it is probably not wise in a generic template.
I’ve put this question in general as I would like to hear your thoughts on this topic. Perhaps later some changes might come out from it.
I suppose it is “cleaner” to separate the JS into <script> tags, but HTML tag attributes are so convenient for generated markup because we don’t have to worry about event listeners, propagation, etc.
My understanding is that unsafe-inline is unsafe if a third party can inject markup into the DOM and cause it to be executed as JS. If the application is safely escaping injected content, or using .innerText instead of .innerHTML and that sort of thing, then there shouldn’t be an issue.
In the case of our standard browse template, I think the only attack vector is someone placing files on the part of the file system being browsed, that can somehow be interpreted as HTML/JS and executed as such.
I think the risk is quite low, but at some point we should probably either extract the inline JS and CSS into script and style tags, or at least triple-check that we’re sanitizing inputs properly.
I can’t remember the details, but the biggest struggle was the svg for the caddy-logo. Eventually, I moved the svg content to an external file, placed it on our “cdn” subdomain.
I am not sure, if all of these changes makes sense in a PR for all Caddy users using the default browse template because of how the files within a directory listing are displayed. I would be quite sure that new issues would be raised like, “the CSP is preventing my video objects to be shown in grid layout” …
That’s interesting. Do you mean Caddy emits the nonce generated in browse.html templateas a HTTP header? If so, then I’d say it probably would fit good as a general template as users can use browse without having to configure any CSP.
Yes, my custom browse.html generates the nonce, uses the nonce for any <style> and <script> and sends it as Response Header using the templates function .RespHeader.Set .
Give me some time to think about the difficulties I’ve had with the embedded svg for the Caddy logo and then I can submit my proposal as a pull request. I think it would be possible to add a subdirective to browse to disable the default content-security-policy header to have a solution available when Caddy users are very unhappy with such content-security-policy.
The problem with the embedded svg for the “Served with caddy” can be seen here: https://alma.stbu.net/
Just open the Developer-Tools and see the issues raised such as:
Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'strict-dynamic' 'nonce-d48bab01-d7d5-4715-94cf-16fad91b9aea'". Either the 'unsafe-inline' keyword, a hash ('sha256-8U4DTM3ZAtnhPIZVOm/BvfynsvX7/vdspJ0hRqKCIdo='), or a nonce ('nonce-...') is required to enable inline execution. Note that hashes do not apply to event handlers, style attributes and javascript: navigations unless the 'unsafe-hashes' keyword is present.
That refers to this line in the browse.html <svg class="caddy-logo" viewBox="0 0 379 114" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;">
I don’t see a Content-Security-Policy (and privacy) friendly way unless:
the caddy-logo <svg>...</svg> content is moved to a file and referenced in the HTML such as <img class="caddy-logo" src="/caddy-logo.svg" alt="Caddy logo"> => see question to Matt below.
add many hashes to the CSP image directive such as sha256-8U4DTM3ZAtnhPIZVOm/BvfynsvX7/vdspJ0hRqKCIdo=
remove the styles from the <svg> such as the colors (compare the nice, colored, original caddy-logo svg appearance here https://alma.stbu.net/without-csp/ and with the removed stlyes due to the Content-Security-Policy not allowing them: https://alma.stbu.net/)
@matt , would it be possible to “embed” the caddy-logo svg into the caddy binary and maybe serve it from an url such as /.well-known/caddy-logo.svg handled “by magic” just like /.well-known/acme-challenge?
If that would be possible, this would allow the first mentioned alternative.
Update:
I think I have found a good solution by moving inline svg styles to a a separate style, where the nonce will be used. After a couple more tests I will start to work on the PR.
EDIT: I had to remove my CSP from my “standards” insert entirely, then add the following to my site. This seems to work, and the rest of my site is protected.
Sorry, I just mean that using the file_server browse directive appears to still require a slightly less strict CSP (with Caddy v2.8.4). It would be great if this functionality would work using a strict CSP such as the statement below:
The PR to have a Content-Security-Policy in the file_server browse was merged on July 6th and is not part of Caddy v2.8.4 (Released June 2nd). You might want to try the v2.9.0-beta.3.
This is how the Content-Security-Policy from Caddy v2.9.0-beta.3 browse will be rated on Securityheaders.com: