From d0e363e66e4d0ff9f9db0818ca8890deb1ebf99c Mon Sep 17 00:00:00 2001 From: Matthieu Jacq <67386567+matthieujacq@users.noreply.github.com> Date: Thu, 5 Oct 2023 17:37:25 +0200 Subject: [PATCH] feat: enable CSP in all environments (local/preview/prod) (#1334) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description Enable CSP in all environments (local/preview/prod). Relies on NEXT_PUBLIC_ENV env variable, which should be `'local'|'preview'|'prod'` # Comparison of old and new CSP values (tested locally) ## Before ### CSP (for prod only) ``` default-src 'self' https://fonts.googleapis.com https://xxx.supabase.co https://api.june.so https://www.quivr.app/; connect-src 'self' https://xxx.supabase.co http://localhost:5050 https://api.june.so https://api.openai.com https://cdn.growthbook.io https://vitals.vercel-insights.com/v1/vitals; img-src 'self' https://www.gravatar.com data:; media-src 'self' https://user-images.githubusercontent.com https://www.quivr.app/ https://quivr-cms.s3.eu-west-3.amazonaws.com; script-src 'unsafe-inline' 'unsafe-eval' https://va.vercel-scripts.com/ https://www.quivr.app/ https://www.google-analytics.com/; frame-ancestors 'none'; style-src 'unsafe-inline' https://www.quivr.app/; ``` ## After ### Prod CSP (iso with before) ``` default-src 'self' https://fonts.googleapis.com https://xxx.supabase.co https://api.june.so https://www.quivr.app/; connect-src 'self' https://xxx.supabase.co http://localhost:5050 https://api.june.so https://api.openai.com https://cdn.growthbook.io https://vitals.vercel-insights.com/v1/vitals; img-src 'self' https://www.gravatar.com data:; media-src 'self' https://user-images.githubusercontent.com https://www.quivr.app/ https://quivr-cms.s3.eu-west-3.amazonaws.com; script-src 'unsafe-inline' 'unsafe-eval' https://va.vercel-scripts.com/ https://www.quivr.app/ https://www.google-analytics.com/; frame-ancestors 'none'; style-src 'unsafe-inline' https://www.quivr.app/; ``` ### Preview CSP ``` default-src 'self' https://fonts.googleapis.com https://xxx.supabase.co https://api.june.so https://preview.quivr.app/; connect-src 'self' https://xxx.supabase.co http://localhost:5050 https://api.june.so https://api.openai.com https://cdn.growthbook.io https://vitals.vercel-insights.com/v1/vitals; img-src 'self' https://www.gravatar.com data:; media-src 'self' https://user-images.githubusercontent.com https://www.quivr.app/ https://quivr-cms.s3.eu-west-3.amazonaws.com; script-src 'unsafe-inline' 'unsafe-eval' https://va.vercel-scripts.com/ https://preview.quivr.app/ https://www.google-analytics.com/; frame-ancestors 'none'; style-src 'unsafe-inline' https://preview.quivr.app/; ``` ### Local CSP ``` default-src 'self' https://fonts.googleapis.com https://xxx.supabase.co https://api.june.so http://localhost:3000 http://localhost:3001; connect-src 'self' https://xxx.supabase.co http://localhost:5050 https://api.june.so https://api.openai.com https://cdn.growthbook.io https://vitals.vercel-insights.com/v1/vitals; img-src 'self' https://www.gravatar.com data:; media-src 'self' https://user-images.githubusercontent.com https://www.quivr.app/ https://quivr-cms.s3.eu-west-3.amazonaws.com; script-src 'unsafe-inline' 'unsafe-eval' https://va.vercel-scripts.com/ http://localhost:3000 http://localhost:3001 https://www.google-analytics.com/; frame-ancestors 'none'; style-src 'unsafe-inline' http://localhost:3000 http://localhost:3001; ``` # 🧪 External checks Syntax checked with https://csp-evaluator.withgoogle.com/ (for the 3 environments). --------- Co-authored-by: gozineb --- frontend/next.config.js | 51 ++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/frontend/next.config.js b/frontend/next.config.js index 56c3db7bc84a..b266558c3eb0 100644 --- a/frontend/next.config.js +++ b/frontend/next.config.js @@ -9,16 +9,12 @@ const nextConfig = { }, // eslint-disable-next-line prefer-arrow/prefer-arrow-functions async headers() { - if (process.env.NEXT_PUBLIC_ENV === "prod") { - return [ - { - source: "/(.*)", - headers: securityHeaders, - }, - ]; - } else { - return []; - } + return [ + { + source: "/(.*)", + headers: securityHeaders, + }, + ]; }, }; @@ -28,7 +24,11 @@ const ContentSecurityPolicy = { "https://fonts.googleapis.com", process.env.NEXT_PUBLIC_SUPABASE_URL, "https://api.june.so", - "https://www.quivr.app/", + { + prod: "https://www.quivr.app/", + preview: "https://preview.quivr.app/", + local: ["http://localhost:3000", "http://localhost:3001"], + }, ], "connect-src": [ "'self'", @@ -50,13 +50,38 @@ const ContentSecurityPolicy = { "'unsafe-inline'", "'unsafe-eval'", "https://va.vercel-scripts.com/", - "https://www.quivr.app/", + { + prod: "https://www.quivr.app/", + preview: "https://preview.quivr.app/", + local: ["http://localhost:3000", "http://localhost:3001"], + }, "https://www.google-analytics.com/", ], "frame-ancestors": ["'none'"], - "style-src": ["'unsafe-inline'", "https://www.quivr.app/"], + "style-src": [ + "'unsafe-inline'", + { + prod: "https://www.quivr.app/", + preview: "https://preview.quivr.app/", + local: ["http://localhost:3000", "http://localhost:3001"], + }, + ], }; +// Resolve environment-specific CSP values +for (const directive of Object.values(ContentSecurityPolicy)) { + for (const [index, resource] of directive.entries()) { + if (typeof resource === "string") { + continue; + } + directive[index] = resource[process.env.NEXT_PUBLIC_ENV]; + if (Array.isArray(directive[index])) { + directive[index] = directive[index].join(" "); + } + } +} + +// Build CSP string const cspString = Object.entries(ContentSecurityPolicy) .map(([key, values]) => `${key} ${values.join(" ")};`) .join(" ");