diff --git a/README.md b/README.md index 78d3e352..8dc82bb4 100644 --- a/README.md +++ b/README.md @@ -154,6 +154,10 @@ Environment variables (will overwrite other server configs) | HMD_S3_SECRET_ACCESS_KEY | no example | AWS secret key | | HMD_S3_REGION | `ap-northeast-1` | AWS S3 region | | HMD_S3_BUCKET | no example | AWS S3 bucket name | +| HMD_HSTS_ENABLE | ` true` | set to enable [HSTS](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security) if HTTPS is also enabled (default is ` true`) | +| HMD_HSTS_INCLUDE_SUBDOMAINS | `true` | set to include subdomains in HSTS (default is `true`) | +| HMD_HSTS_MAX_AGE | `31536000` | max duration in seconds to tell clients to keep HSTS status (default is a year) | +| HMD_HSTS_PRELOAD | `true` | whether to allow preloading of the site's HSTS status (e.g. into browsers) | Application settings `config.json` --- @@ -166,6 +170,7 @@ Application settings `config.json` | port | `80` | web app port | | alloworigin | `['localhost']` | domain name whitelist | | usessl | `true` or `false` | set to use ssl server (if true will auto turn on `protocolusessl`) | +| hsts | `{"enable": "true", "maxAgeSeconds": "31536000", "includeSubdomains": "true", "preload": "true"}` | [HSTS](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security) options to use with HTTPS (default is the example value, max age is a year) | | protocolusessl | `true` or `false` | set to use ssl protocol for resources path (only applied when domain is set) | | urladdport | `true` or `false` | set to add port on callback url (port 80 or 443 won't applied) (only applied when domain is set) | | usecdn | `true` or `false` | set to use CDN resources or not (default is `true`) | diff --git a/app.js b/app.js index 1508781c..62e6627d 100644 --- a/app.js +++ b/app.js @@ -97,11 +97,16 @@ var sessionStore = new SequelizeStore({ app.use(compression()) // use hsts to tell https users stick to this -app.use(helmet.hsts({ - maxAge: 31536000 * 1000, // 365 days - includeSubdomains: true, - preload: true -})) +if (config.hsts.enable) { + app.use(helmet.hsts({ + maxAge: config.hsts.maxAgeSeconds * 1000, + includeSubdomains: config.hsts.includeSubdomains, + preload: config.hsts.preload + })) +} else if (config.usessl) { + logger.info('Consider enabling HSTS for extra security:') + logger.info('https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security') +} i18n.configure({ locales: ['en', 'zh', 'fr', 'de', 'ja', 'es', 'ca', 'el', 'pt', 'it', 'tr', 'ru', 'nl', 'hr', 'pl', 'uk', 'hi', 'sv', 'eo', 'da'], diff --git a/app.json b/app.json index e06720f4..1de6b7db 100644 --- a/app.json +++ b/app.json @@ -23,7 +23,22 @@ "description": "Specify database type. See sequelize available databases. Default using postgres", "value": "postgres" }, - + "HMD_HSTS_ENABLE": { + "description": "whether to also use HSTS if HTTPS is enabled", + "required": false + }, + "HMD_HSTS_MAX_AGE": { + "description": "max duration, in seconds, to tell clients to keep HSTS status", + "required": false + }, + "HMD_HSTS_INCLUDE_SUBDOMAINS": { + "description": "whether to tell clients to also regard subdomains as HSTS hosts", + "required": false + }, + "HMD_HSTS_PRELOAD": { + "description": "whether to allow at all adding of the site to HSTS preloads (e.g. in browsers)", + "required": false + }, "HMD_DOMAIN": { "description": "domain name", "required": false diff --git a/config.json.example b/config.json.example index 87c04ed0..e2d774c7 100644 --- a/config.json.example +++ b/config.json.example @@ -6,6 +6,9 @@ } }, "development": { + "hsts": { + "enable": false + }, "db": { "dialect": "sqlite", "storage": "./db.hackmd.sqlite" @@ -13,6 +16,12 @@ }, "production": { "domain": "localhost", + "hsts": { + "enable": "true", + "maxAgeSeconds": "31536000", + "includeSubdomains": "true", + "preload": "true" + }, "db": { "username": "", "password": "", diff --git a/lib/config/default.js b/lib/config/default.js index a14a4294..f4c45e3d 100644 --- a/lib/config/default.js +++ b/lib/config/default.js @@ -7,6 +7,12 @@ module.exports = { urladdport: false, alloworigin: ['localhost'], usessl: false, + hsts: { + enable: true, + maxAgeSeconds: 31536000, + includeSubdomains: true, + preload: true + }, protocolusessl: false, usecdn: true, allowanonymous: true, diff --git a/lib/config/environment.js b/lib/config/environment.js index c108a6f9..40b7e09f 100644 --- a/lib/config/environment.js +++ b/lib/config/environment.js @@ -8,6 +8,12 @@ module.exports = { port: process.env.HMD_PORT, urladdport: toBooleanConfig(process.env.HMD_URL_ADDPORT), usessl: toBooleanConfig(process.env.HMD_USESSL), + hsts: { + enable: toBooleanConfig(process.env.HMD_HSTS_ENABLE), + maxAgeSeconds: process.env.HMD_HSTS_MAX_AGE, + includeSubdomains: toBooleanConfig(process.env.HMD_HSTS_INCLUDE_SUBDOMAINS), + preload: toBooleanConfig(process.env.HMD_HSTS_PRELOAD) + }, protocolusessl: toBooleanConfig(process.env.HMD_PROTOCOL_USESSL), alloworigin: process.env.HMD_ALLOW_ORIGIN ? process.env.HMD_ALLOW_ORIGIN.split(',') : undefined, usecdn: toBooleanConfig(process.env.HMD_USECDN),