diff --git a/next.config.js b/next.config.js index 9c12086..88a199e 100644 --- a/next.config.js +++ b/next.config.js @@ -2,6 +2,58 @@ const withPlugins = require('next-compose-plugins'); const withFonts = require('next-fonts'); const withSvgr = require('@newhighsco/next-plugin-svgr'); +const ContentSecurityPolicy = ` + default-src 'self'; + script-src 'self' ${ + process.env.NODE_ENV == 'development' ? "'unsafe-eval' " : '' + }'unsafe-inline' *.ctfassets.net *.youtube.com *.twitter.com; + child-src 'self' *.ctfassets.net *.youtube.com *.twitter.com; + style-src 'self' 'unsafe-inline' *.googleapis.com; + img-src 'self' blob: data: *.ctfassets.net *.youtube.com *.twitter.com; + media-src 'self'; + connect-src *; + font-src 'self' blob: data: fonts.gstatic.com maxcdn.bootstrapcdn.com; + worker-src 'self' blob:; +`; + +const securityHeaders = () => { + const headers = [ + { + key: 'X-DNS-Prefetch-Control', + value: 'on', + }, + { + key: 'Strict-Transport-Security', + value: 'max-age=63072000; includeSubDomains; preload', + }, + { + key: 'X-XSS-Protection', + value: '1; mode=block', + }, + { + key: 'X-Frame-Options', + value: 'SAMEORIGIN', + }, + { + key: 'Permissions-Policy', + value: 'camera=(), microphone=(), geolocation=(), interest-cohort=()', + }, + { + key: 'X-Content-Type-Options', + value: 'nosniff', + }, + { + key: 'Referrer-Policy', + value: 'strict-origin-when-cross-origin', + }, + { + key: 'Content-Security-Policy', + value: ContentSecurityPolicy.replace(/\n/g, ''), + }, + ]; + return headers; +}; + const nextConfig = { env: { CONTENTFUL_SPACE_ID: process.env.CONTENTFUL_SPACE_ID, @@ -11,6 +63,14 @@ const nextConfig = { CAMPAIGN_MONITOR_API_KEY: process.env.CAMPAIGN_MONITOR_API_KEY, CAMPAIGN_MONITOR_LIST_API_ID: process.env.CAMPAIGN_MONITOR_LIST_API_ID, }, + async headers() { + return [ + { + source: '/(.*)', + headers: securityHeaders(), + }, + ]; + }, images: { domains: ['downloads.ctfassets.net', 'images.ctfassets.net'], },