feat(nginx): add HSTS + Permissions-Policy to chat.lotusguild.org (P6-4)
Lint / Shell (shellcheck) (push) Successful in 10s
Lint / JS (eslint) (push) Successful in 7s
Lint / Python (ruff) (push) Successful in 6s
Lint / Python deps (pip-audit) (push) Successful in 31s
Lint / Secret scan (gitleaks) (push) Successful in 5s

Adds Strict-Transport-Security (2y, includeSubDomains, preload) and a
Permissions-Policy that allows only the features the app uses (camera/mic/
display-capture for calls, geolocation for location share, autoplay/fullscreen/
encrypted-media) and denies the rest. Complements the existing X-Frame/CSP/
Referrer headers.

Apply: reload nginx on the LXC. TLS terminates upstream (listen 80), so verify
the header reaches the browser (front proxy must pass it through) — else set
HSTS at the TLS terminator. Verify a call + location share still work.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-02 14:41:08 -04:00
parent 7618b3b091
commit 6293a62e47
+10
View File
@@ -23,6 +23,16 @@ server {
add_header X-Content-Type-Options nosniff always; add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always; add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy strict-origin-when-cross-origin always; add_header Referrer-Policy strict-origin-when-cross-origin always;
# HSTS: TLS terminates upstream (this server is listen 80), so this reaches
# the browser only if the front proxy passes upstream response headers
# through; otherwise set it at the TLS terminator. includeSubDomains covers
# all *.lotusguild.org (all HTTPS); `preload` is inert until submitted to
# hstspreload.org.
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# Permissions-Policy: allow only what the app uses (self) — calls
# (camera/microphone/display-capture), location share (geolocation), sounds
# (autoplay), Element Call (fullscreen/encrypted-media) — and deny the rest.
add_header Permissions-Policy "accelerometer=(), autoplay=(self), camera=(self), display-capture=(self), encrypted-media=(self), fullscreen=(self), geolocation=(self), gyroscope=(), magnetometer=(), microphone=(self), midi=(), payment=(), usb=()" always;
# Block all source map files and dotfiles from public access # Block all source map files and dotfiles from public access
location ~* \.(js|css)\.map$ { location ~* \.(js|css)\.map$ {