Files
webmail-client/docker/nginx-security.conf
T

32 lines
2.3 KiB
Plaintext
Raw Normal View History

# 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;