Custom CSP for Payload in Express server with frontend app

default discord avatar
58bits7 months ago

Posting here in case anyone else comes across this. We have a custom express server serving both Payload and our frontend app. Payload admin is available via

/admin

The frontend app and Payload have quite different CSP settings. If you're using

https://helmetjs.github.io/

- then you can chain helmet middleware and return different policies depending on the request path. For example...



// CSP policy via helmet
app.use(function (req, res, next) {
  let middleware
  // If we've mounted Payload CMS on /admin - change the CSP to suit.
  if (req.path.startsWith('/admin')) {
    middleware = helmet({
      contentSecurityPolicy: {
        'script-src': [
            "'self'"
          ],
          'img-src': ["'self'", 'data:', 'cdn.yourcdn.com'],
          'media-src': ["'self'", 'data:', 'cdn.yourcdn.com'],
          'default-src': ["'self'"]
      }
    })
  } else {
    middleware = helmet({
      crossOriginEmbedderPolicy: false,
      contentSecurityPolicy: {
        // NOTE: Remove reportOnly when you're ready to enforce this CSP
        // reportOnly: true,
        directives: {
          'connect-src': [
            ENVIRONMENT === 'development' ? 'ws:' : null,
            "'self'",
          ].filter(Boolean),
          'script-src': [
            "'strict-dynamic'",
            "'self'", // Ignored by CSP 3 compliant browsers when strict-dynamic - here for backwards compat.
            "'unsafe-inline'", // Ignored by CSP 3 compliant browsers when strict-dynamic - here for backwards compat.
            'https:', // Ignored by CSP 3 compliant browsers when strict-dynamic - here for backwards compat.
            'http:', // Ignored by CSP 3 compliant browsers when strict-dynamic - here for backwards compat.
            (_, res) => `'nonce-${res.locals.cspNonce}'`
          ],
          'script-src-attr': [
            (_, res) => `'nonce-${res.locals.cspNonce}'`
          ],
          'font-src': ["'self'"],
          'frame-src': ["'self'"],
          'img-src': ["'self'", 'data:', 'cdn.yourcdn.com'],
          'media-src': ["'self'", 'data:', 'cdn.yourcdn.com'],
          'default-src': ["'self'"],
          'upgrade-insecure-requests': null
        }
      }
    })
  }

  middleware(req, res, next)
})

Hope this helps ;-)

    Star on GitHub

    Star

    Chat on Discord

    Discord

    online

    Can't find what you're looking for?

    Get help straight from the Payload team with an Enterprise License.