32 lines
2.3 KiB
Plaintext
32 lines
2.3 KiB
Plaintext
# Security headers for every response of the front door — the app shell, the
|
|||
|
|
# static files and the API alike.
|
||
|
|
#
|
||
|
|
# Included at server level by nginx-app.conf AND inside every location that
|
||
|
|
# adds a header of its own: nginx drops ALL inherited add_header lines in a
|
||
|
|
# location that has any add_header, which is how index.html once went out with
|
||
|
|
# only its Cache-Control (security report, finding 1). A new location with an
|
||
|
|
# add_header must include this file too.
|
||
|
|
#
|
||
|
|
# Content-Security-Policy, by directive:
|
||
|
|
# script-src 'self' the Vite bundles, plugin bundles (/api/plugins/…) and
|
||
|
|
# workers are all same-origin; no inline script, no eval
|
||
|
|
# (pdf.js is told not to try).
|
||
|
|
# style-src 'unsafe-inline': React and the plugins set style
|
||
|
|
# attributes, and message HTML carries its own <style>.
|
||
|
|
# img-src / font-src https:/http: because an email whose images the user
|
||
|
|
# chose to load fetches them from the sender's servers
|
||
|
|
# (the message frame is srcdoc, so it shares this policy).
|
||
|
|
# connect-src the API and the live-update WebSocket on this host
|
||
|
|
# ($http_host: with the port, for LAN access on WEB_PORT).
|
||
|
|
# frame-ancestors 'self', not 'none': printing an attachment loads it in
|
||
|
|
# a hidden frame of our own. No other site may frame us.
|
||
|
|
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https: http:; font-src 'self' data: https:; media-src 'self' blob:; connect-src 'self' wss://$http_host ws://$http_host; worker-src 'self' blob:; frame-src 'self' blob:; manifest-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'self'" always;
|
||
|
|
add_header X-Frame-Options SAMEORIGIN always;
|
||
|
|
add_header X-Content-Type-Options nosniff always;
|
||
|
|
add_header Referrer-Policy no-referrer always;
|
||
|
|
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=()" always;
|
||
|
|
# Only on requests that reached the reverse proxy over HTTPS ($hsts is empty
|
||
|
|
# otherwise, and nginx sends no header with an empty value): plain-HTTP LAN
|
||
|
|
# access on WEB_PORT keeps working.
|
||
|
|
add_header Strict-Transport-Security $hsts always;
|