Changeset 81bb9c5 in Klonkt


Ignore:
Timestamp:
06/28/2026 03:44:15 PM (2 months ago)
Author:
Robin Genis <roboburr@…>
Branches:
main
Children:
897c33b
Parents:
f7d142f
git-author:
Robin Genis <roboburr@…> (06/28/2026 03:42:45 PM)
git-committer:
Robin Genis <roboburr@…> (06/28/2026 03:44:15 PM)
Message:

chore(hsts): make includeSubDomains+preload opt-in via HSTS_STRICT

Default ships a plain long max-age (safe on any domain a self-hoster runs). The
aggressive includeSubDomains+preload (which affect the operator's other subdomains and
can bake their domain into browsers) are opt-in via HSTS_STRICT=1, set on domains we own.

  • server.js — build hsts options from HSTS_STRICT
  • .env.example — document HSTS_STRICT
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • .env.example

    rf7d142f r81bb9c5  
    2020# set it for production so email/login links point at the right place.
    2121PUBLIC_BASE_URL=
     22
     23# Strict HSTS. By default Klonkt sends a plain long max-age (safe on any domain).
     24# Set HSTS_STRICT=1 ONLY if Klonkt owns the whole domain incl. all its subdomains:
     25# it adds `includeSubDomains; preload`, which forces every subdomain to HTTPS and can
     26# get your domain baked into browsers near-permanently. Leave unset if unsure.
     27# HSTS_STRICT=1
    2228
    2329# ── Administrator ───────────────────────────────────────────────────
  • src/server.js

    rf7d142f r81bb9c5  
    9696app.use((req, res, next) => { res.locals.cspNonce = crypto.randomBytes(16).toString('base64'); next(); });
    9797
     98// HSTS. The default ships a plain long max-age — safe on ANY domain. includeSubDomains +
     99// preload are aggressive (they affect the operator's OTHER subdomains and can get their
     100// domain baked into browsers near-permanently), so they're opt-in via HSTS_STRICT=1 — set
     101// only on domains you fully own (e.g. the klonkt.com fleet). Self-hosters get the safe default.
     102// NB: Helmet defaults includeSubDomains to true, so the safe default must disable it explicitly.
     103const hstsOptions = { maxAge: 31536000, includeSubDomains: false, preload: false };
     104if (process.env.HSTS_STRICT === '1') { hstsOptions.includeSubDomains = true; hstsOptions.preload = true; }
     105
    98106app.use(helmet({
    99107  contentSecurityPolicy: {
     
    139147    },
    140148  },
    141   hsts: { maxAge: 31536000, includeSubDomains: true, preload: true },
     149  hsts: hstsOptions,
    142150  frameguard: { action: 'sameorigin' },
    143151  referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
Note: See TracChangeset for help on using the changeset viewer.