Please use https://securityheaders.com/ if you want to do some testing yourself and get some feedback. But let's drop in a few thoughts on this:
We should definitely implement this headers as strict as possible to only use the browser features Navidrome needs. Meaning disabling features like webcam, geo, microphone et cetera. This would limit the possibilities extremely when an XSS injection is possible.
This Header we should also include with the "same-origin" option by default. Meaning simply that it isn't possible to frame Navidrome (iframes) and do some clickjacking attacks. Although I can imaging in some cases some advanced users might want to configure and frame it anyway, so I suggest this header should be default on "same-origin" but configurable in Settings.
Mainly for older browsers but lets add it with the "nosniff" option. Doesn't hurt anyone. Possibly prevents content type sniffing.
Yes, should use with "1; mode=block" value. Does not work in all browsers but won't affect browsers that don't support it. Should be enabled in the browser by default in most cases. Just a case of better be safe then sorry when XSS is possible and the browser config sucks.
Only relevant when we start to refer to external URL's, which I believe is not the case currently. Nevertheless I would already set it up with the "no-referrer" or "same-origin".
Other HTTP security headers such as Expect-CT, Expect-Staple, HSTS, HPKP should be left to advanced users to configure themselves, only when SSL is enabled. Maybe we could facilitate adding custom HTTP headers from a config file?
The XSS thingy is a bad idea. X-Content-Type-Options is a thing from the past, I doubt that navidrome is usable on antediluvian browsers anyway.
As for the CSP directive, it's a good idea, especially coupled with Trusted Types.
Probably one for the documentation or for future reference to anybody who finds this useful.
I did some testing using Traefik as my reverse proxy and found the following security options were suitable for Navidrome:
stsSeconds: 2592000
stsIncludeSubdomains: true
browserXssFilter: true
contentTypeNosniff: true
forceSTSHeader: true
frameDeny: true
referrerPolicy: same-origin
contentSecurityPolicy: |
default-src https://<redacted domain/subdomain>;
script-src https://<redacted domain/subdomain> 'unsafe-inline'
featurePolicy: |
autoplay 'none';
camera: 'none';
display-capture 'none';
microphone: 'none';
usb: 'none'
This is obviously not my entire Traefik config but the relevant portion I used for my middlewares declarations. These were enough to get an 'A' score from a security headers scan.
This mitigates the need to add them into Navidrome's response headers, but not everyone is going to have a reverse proxy and HTTPS setup.
Thanks all! I'm gonna add a security middleware: https://github.com/unrolled/secure
Any suggestions on the configuration we should use?
(of course none of the SSL/STS stuff should be implemented, as we don't support SSL termination on Navidrome itself)
Neat, that's really useful. I saw that Traefik referred to this same handler in their docs
I guess with using that, be mindful that people may use bare domain's or subdomains so the Content-Security-Policy and Feature-Policy will probably need to take that into consideration.
馃憤
I'm gonna leave this open, to track the work on the CSP implementation
With the new Feature-Policy in place, I'm seeing these messages in Chome's console:

Not sure if this is caused by Feature Policy been renamed to Permissions Policy, will have to investigate. If anyone knows anything about it, please chime in.