From 70ab331610c74fa4cd18a75a18c8a6653f614844 Mon Sep 17 00:00:00 2001 From: Iqbal AHmed Date: Thu, 18 Jan 2024 13:42:23 +0000 Subject: [PATCH] PP-11850 Update CSP > report-to - Missed out the `Reporting-Endpoints` header. - Required slightly rewriting how we specify the CSP in Helmet. --- app/middleware/csp.js | 14 +++++++++++--- app/routes.js | 5 +++-- server.js | 4 ++-- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/app/middleware/csp.js b/app/middleware/csp.js index 58b2acd68..0eb06794d 100644 --- a/app/middleware/csp.js +++ b/app/middleware/csp.js @@ -31,6 +31,8 @@ const styleSourceCardDetails = ['\'self\'', '\'unsafe-eval\'', '\'unsafe-inline\ const formActionWP3DS = ['\'self\'', 'https://centinelapi.cardinalcommerce.com/V1/Cruise/Collect', 'https://secure-test.worldpay.com/shopper/3ds/ddc.html'] +const CSP_REPORTING_ENDPOINT_NAME = 'csp-endpoint' + // Direct redirect use case lets post to any given site const formActionCardDetails = (req, res) => { if (res.locals && res.locals.service && @@ -50,9 +52,14 @@ const connectSourceCardDetails = ['\'self\'', 'https://www.google-analytics.com' const skipSendingCspHeader = (req, res, next) => { next() } +const setResponseCspReportingEndpointName = (req, res, next) => { + res.setHeader('Reporting-Endpoints', `${CSP_REPORTING_ENDPOINT_NAME}="${paths.csp.path}"`) + next() +} + const cardDetailsCSP = helmet.contentSecurityPolicy({ directives: { - reportTo: paths.csp.path, + reportTo: CSP_REPORTING_ENDPOINT_NAME, frameSrc: frameAndChildSourceCardDetails, childSrc: frameAndChildSourceCardDetails, imgSrc: imgSourceCardDetails, @@ -73,7 +80,7 @@ const cardDetailsCSP = helmet.contentSecurityPolicy({ const worldpayIframeCSP = helmet.contentSecurityPolicy({ directives: { - reportTo: paths.csp.path, + reportTo: CSP_REPORTING_ENDPOINT_NAME, defaultSrc: CSP_NONE, formAction: formActionWP3DS, frameAncestors: CSP_SELF, @@ -145,5 +152,6 @@ module.exports = { rateLimitMiddleware, captureEventMiddleware, requestParseMiddleware, - detectErrorsMiddleware + detectErrorsMiddleware, + setResponseCspReportingEndpointName } diff --git a/app/routes.js b/app/routes.js index 3a8a3e386..208e40f20 100644 --- a/app/routes.js +++ b/app/routes.js @@ -26,7 +26,8 @@ const { rateLimitMiddleware, requestParseMiddleware, detectErrorsMiddleware, - captureEventMiddleware + captureEventMiddleware, + setResponseCspReportingEndpointName } = require('./middleware/csp') const decryptCardData = require('./middleware/decrypt-card-data')(process.env) @@ -78,7 +79,7 @@ exports.bind = function (app) { app.post(paths.csp.path, cspMiddlewareStack) // CSP violation monitoring app.post(paths.log.path, chargeCookieRequiredMiddlewareStack, log) - app.get(card.new.path, standardMiddlewareStack, cardDetails, charge.new) + app.get(card.new.path, standardMiddlewareStack, setResponseCspReportingEndpointName, cardDetails, charge.new) app.get(card.authWaiting.path, standardMiddlewareStack, charge.authWaiting) app.get(card.captureWaiting.path, standardMiddlewareStack, charge.captureWaiting) app.post(card.create.path, standardMiddlewareStack, charge.create) diff --git a/server.js b/server.js index 0ec91db4d..2a48fd59e 100644 --- a/server.js +++ b/server.js @@ -22,7 +22,7 @@ const session = require('./app/utils/session') const i18nConfig = require('./config/i18n') const i18nPayTranslation = require('./config/pay-translation') const Sentry = require('./app/utils/sentry.js').initialiseSentry() -const { worldpayIframe } = require('./app/middleware/csp') +const { setResponseCspReportingEndpointName, worldpayIframe } = require('./app/middleware/csp') const correlationHeader = require('./app/middleware/correlation-header') const errorHandlers = require('./app/middleware/error-handlers') @@ -131,7 +131,7 @@ function initialiseTemplateEngine (app) { function initialisePublic (app) { app.use('/.well-known/apple-developer-merchantid-domain-association.txt', express.static(path.join(__dirname, `/app/assets/apple-pay/${process.env.ENVIRONMENT}/apple-developer-merchantid-domain-association.txt`))) - app.use('/public/worldpay', worldpayIframe, express.static(path.join(__dirname, '/public/worldpay/'), publicCaching)) + app.use('/public/worldpay', setResponseCspReportingEndpointName, worldpayIframe, express.static(path.join(__dirname, '/public/worldpay/'), publicCaching)) app.use('/public', express.static(path.join(__dirname, '/public'), publicCaching)) app.use('/public', express.static(path.join(__dirname, '/app/data'), publicCaching)) app.use('/public', express.static(path.join(__dirname, '/govuk_modules/govuk-country-and-territory-autocomplete'), publicCaching))