Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use strict https headers and redirect from http to https in production mode #410

Merged
merged 26 commits into from
Feb 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9231bc8
Set Strict-Transport-Security header in production
frankieroberto Nov 13, 2024
5311296
Remove older commented-out https code
frankieroberto Nov 13, 2024
6c0a9cc
Update changelog
frankieroberto Nov 13, 2024
c9deeae
Merge branch 'main' into use-strict-https-in-production
frankieroberto Nov 19, 2024
e8b6612
Merge branch 'main' into use-strict-https-in-production
frankieroberto Nov 22, 2024
e5bbedf
Merge branch 'main' into use-strict-https-in-production
frankieroberto Dec 10, 2024
77c52f6
Merge branch 'main' into use-strict-https-in-production
frankieroberto Dec 10, 2024
1204315
Merge branch 'main' into use-strict-https-in-production
frankieroberto Jan 26, 2025
e9cb08e
Update changelog
frankieroberto Jan 26, 2025
9347136
Include subdomains in HST header
frankieroberto Feb 10, 2025
048da66
Merge branch 'main' into use-strict-https-in-production
frankieroberto Feb 10, 2025
daedfa0
Add Content-Security-Policy
frankieroberto Feb 10, 2025
e79ddf6
Move the production headers middleware up
frankieroberto Feb 10, 2025
ddace40
Refactor to move production headers into lib/
frankieroberto Feb 10, 2025
b40000f
Bugfix
frankieroberto Feb 10, 2025
ddc5108
Require the production middleware
frankieroberto Feb 10, 2025
246d0af
Merge branch 'main' into use-strict-https-in-production
frankieroberto Feb 14, 2025
9d375e5
Add redirect to https if served over http
frankieroberto Feb 14, 2025
88d8db3
Add temporary debug
frankieroberto Feb 14, 2025
16ede58
Fix stupid typo
frankieroberto Feb 14, 2025
307c977
HTTP headers are lowercase within req.headers
frankieroberto Feb 14, 2025
f4106a1
Add comment
frankieroberto Feb 14, 2025
fca98e5
Code style fixes
frankieroberto Feb 14, 2025
3c94d55
Use the trust proxy setting
frankieroberto Feb 14, 2025
3e0b6eb
Fix typo
frankieroberto Feb 14, 2025
61e4441
Update CHANGELOG.md
frankieroberto Feb 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## [Unreleased]

- Use strict https and automatic http to https redirects in production mode - ([PR 410](https://github.com/nhsuk/nhsuk-prototype-kit/pull/410))

### Updated

- Updated .devcontainer to remove the image attribute ([PR 451](https://github.com/nhsuk/nhsuk-prototype-kit/pull/451))
Expand Down
13 changes: 11 additions & 2 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ dotenv.config();
// Local dependencies
const packageInfo = require('./package.json');
const authentication = require('./lib/middleware/authentication');
const production = require('./lib/middleware/production');
const automaticRouting = require('./lib/middleware/auto-routing');
const config = require('./app/config');
const locals = require('./app/locals');
Expand Down Expand Up @@ -77,8 +78,10 @@ const sessionOptions = {
},
};

// Authentication
app.use(authentication);
if (process.env.NODE_ENV === 'production') {
app.use(production);
app.use(authentication);
}

// Support session data in cookie or memory
if (useCookieSessionStore === 'true') {
Expand Down Expand Up @@ -148,6 +151,12 @@ app.use(locals(config));
app.set('view engine', 'html');
exampleTemplatesApp.set('view engine', 'html');

// This setting trusts the X-Forwarded headers set by
// a proxy and uses them to set the standard header in
// req. This is needed for hosts like Heroku.
// See https://expressjs.com/en/guide/behind-proxies.html
app.set('trust proxy', 1);

// Middleware to serve static assets
app.use(express.static(path.join(__dirname, 'public')));
app.use('/nhsuk-frontend', express.static(path.join(__dirname, 'node_modules/nhsuk-frontend/packages')));
Expand Down
5 changes: 1 addition & 4 deletions lib/middleware/authentication.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ const allowedPathsWhenUnauthenticated = [
];

const encryptedPassword = encryptPassword(process.env.PROTOTYPE_PASSWORD);
const nodeEnv = process.env.NODE_ENV || 'development';

// Redirect the user to the password page, with
// the current page path set as the returnURL in a query
Expand All @@ -34,9 +33,7 @@ function showNoPasswordError(res) {
}

function authentication(req, res, next) {
if (nodeEnv !== 'production') {
next();
} else if (!process.env.PROTOTYPE_PASSWORD) {
if (!process.env.PROTOTYPE_PASSWORD) {
showNoPasswordError(res);
} else if (allowedPathsWhenUnauthenticated.includes(req.path)) {
next();
Expand Down
22 changes: 22 additions & 0 deletions lib/middleware/production.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// This Express middleware function sets some
// HTTP headers which should only be set in deployed
// environments

function production(req, res, next) {
// Set Strict-Transport-Security header to
// ensure that browsers only use HTTPS
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');

// Set content security policy to upgrade
// all HTTP requests to HTTPS
res.setHeader('Content-Security-Policy', 'upgrade-insecure-requests');

// Redirect HTTP requests to HTTPS
if (req.protocol !== 'https') {
res.redirect(302, `https://${req.get('Host')}${req.url}`);
} else {
next();
}
}

module.exports = production;
15 changes: 0 additions & 15 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,21 +110,6 @@ exports.findAvailablePort = function (app, callback) {
}
*/

/*
// Redirect HTTP requests to HTTPS
exports.forceHttps = function (req, res, next) {
if (req.headers['x-forwarded-proto'] !== 'https') {
console.log('Redirecting request to https')
// 302 temporary - this is a feature that can be disabled
return res.redirect(302, 'https://' + req.get('Host') + req.url)
}

// Mark proxy as secure (allows secure cookies)
req.connection.proxySecure = true
next()
}
*/

/*
// Synchronously get the URL for the latest release on GitHub and cache it
exports.getLatestRelease = function () {
Expand Down