Skip to content

Commit

Permalink
MAP-1878: webSecurity update
Browse files Browse the repository at this point in the history
  • Loading branch information
ashleygyngell committed Feb 7, 2025
1 parent 96c4cdd commit ae5bb12
Showing 1 changed file with 29 additions and 16 deletions.
45 changes: 29 additions & 16 deletions server/middleware/setUpWebSecurity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,47 @@ import config from '../config'
export default function setUpWebSecurity(): Router {
const router = express.Router()

const gaHosts = ['*.googletagmanager.com', '*.google-analytics.com', '*.analytics.google.com']

//
// Secure code best practice - see:
// 1. https://expressjs.com/en/advanced/best-practice-security.html,
// 2. https://www.npmjs.com/package/helmet
router.use((_req: Request, res: Response, next: NextFunction) => {
res.locals.cspNonce = crypto.randomBytes(16).toString('hex')
next()
})

// This nonce allows us to use scripts with the use of the `cspNonce` local, e.g (in a Nunjucks template):
// <script nonce="{{ cspNonce }}">
// or
// <link href="http://example.com/" rel="stylesheet" nonce="{{ cspNonce }}">
// This ensures only scripts we trust are loaded, and not anything injected into the
// page by an attacker.
const connectSrc = ["'self'", (_req: Request, res: Response) => `'nonce-${res.locals.cspNonce}'`]
const scriptSrc = ["'self'", (_req: Request, res: Response) => `'nonce-${res.locals.cspNonce}'`]
const styleSrc = ["'self'", (_req: Request, res: Response) => `'nonce-${res.locals.cspNonce}'`]
const imgSrc = ["'self'", 'data:']
const fontSrc = ["'self'", config.apis.frontendComponents.url]
const formAction = [`'self' ${config.apis.hmppsAuth.externalUrl} ${config.serviceUrls.digitalPrisons}`]
const mediaSrc = ["'self'"]

if (config.apis.frontendComponents.url) {
scriptSrc.push(config.apis.frontendComponents.url)
styleSrc.push(config.apis.frontendComponents.url)
imgSrc.push(config.apis.frontendComponents.url)
fontSrc.push(config.apis.frontendComponents.url)
}

router.use(
helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
// This nonce allows us to use scripts with the use of the `cspNonce` local, e.g (in a Nunjucks template):
// <script nonce="{{ cspNonce }}">
// or
// <link href="http://example.com/" rel="stylesheet" nonce="{{ cspNonce }}">
// This ensures only scripts we trust are loaded, and not anything injected into the
// page by an attacker.
scriptSrc: ["'self'", (_req: Request, res: Response) => `'nonce-${res.locals.cspNonce}'`, ...gaHosts],
styleSrc: ["'self'", (_req: Request, res: Response) => `'nonce-${res.locals.cspNonce}'`],
fontSrc: ["'self'", config.apis.frontendComponents.url],
formAction: [`'self' ${config.apis.hmppsAuth.externalUrl}`],
connectSrc: ["'self'", ...gaHosts],
imgSrc: ["'self'", ...gaHosts],
mediaSrc: ["'self'", ...gaHosts],
connectSrc,
scriptSrc,
styleSrc,
fontSrc,
formAction,
imgSrc,
mediaSrc,
},
},
crossOriginEmbedderPolicy: true,
Expand Down

0 comments on commit ae5bb12

Please sign in to comment.