Skip to content

Commit

Permalink
Update CSP and move CSP & CORS to middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
max-debug022 committed Dec 30, 2024
1 parent 72f687b commit 96ba580
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 33 deletions.
14 changes: 1 addition & 13 deletions site/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,11 @@ const nextConfig = {
optimizePackageImports: ["@comet/cms-site"],
},
poweredByHeader: false,
// https://nextjs.org/docs/advanced-features/security-headers (Content-Security-Policy and CORS are set in middleware.ts)
// https://nextjs.org/docs/advanced-features/security-headers (Content-Security-Policy and CORS are set in middleware.ts/configureResponse.ts)
headers: async () => [
{
source: "/:path*",
headers: [
{
key: "Content-Security-Policy",
value: generateCSP(),
},
{
key: "Strict-Transport-Security", // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
value: "max-age=63072000; includeSubDomains; preload", // 2 years (recommended when subdomains are included)
Expand Down Expand Up @@ -92,14 +88,6 @@ const nextConfig = {
key: "Referrer-Policy", // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
value: "same-origin", // Only use referer on own domain.
},
...(process.env.ADMIN_URL
? [
{
key: "Access-Control-Allow-Origin",
value: process.env.ADMIN_URL,
},
]
: []),
],
},
],
Expand Down
58 changes: 38 additions & 20 deletions site/src/util/configureResponse.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,46 @@
import { NextResponse } from "next/server";
import * as process from "process";

export function configureResponse(response: NextResponse) {
response.headers.set(
"Content-Security-Policy",
`
default-src 'self';
form-action 'self';
object-src 'none';
img-src 'self' https: data:${process.env.NODE_ENV === "development" ? " http:" : ""};
media-src 'self' https: data:${process.env.NODE_ENV === "development" ? " http:" : ""};
style-src 'self' 'unsafe-inline';
font-src 'self' https: data:;
script-src 'self' 'unsafe-inline' https:${process.env.NODE_ENV === "development" ? " 'unsafe-eval'" : ""};
connect-src 'self' https:${process.env.NODE_ENV === "development" ? " http:" : ""};
frame-ancestors ${process.env.ADMIN_URL ?? "none"};
upgrade-insecure-requests;
block-all-mixed-content;
frame-src 'self' https://*.youtube.com https://*.youtube-nocookie.com;
`
.replace(/\s{2,}/g, " ")
.trim(),
);
setContentSecurityPolicy(response);

if (process.env.ADMIN_URL) {
response.headers.set("Access-Control-Allow-Origin", process.env.ADMIN_URL);
}
return response;
}

function setContentSecurityPolicy(response: NextResponse) {
type ContentSecurityPolicyDirective = {
directive: string;
values: string[];
};

const siteContentSecurityPolicyDirectives: ContentSecurityPolicyDirective[] = [
{ directive: "default-src", values: ["'none'"] }, // Restrict any content not explicitly allowed
{ directive: "style-src-elem", values: ["'self'", "'unsafe-inline'"] },
{ directive: "script-src-elem", values: ["'self'", "'unsafe-inline'"] },
{ directive: "img-src", values: ["'self'", "data:", process.env.API_URL ?? ""] },
{ directive: "style-src-attr", values: ["'unsafe-inline'"] },
{ directive: "font-src", values: ["'self'", "data:"] },
{ directive: "frame-ancestors", values: [process.env.ADMIN_URL ?? "https:"] },
];

const environmentDependentContentSecurityPolicyDirectives: ContentSecurityPolicyDirective[] =
process.env.NODE_ENV === "development"
? [
{ directive: "script-src", values: ["'unsafe-eval'"] }, // Needed in local development
{ directive: "connect-src", values: ["ws:"] }, // Used for hot reloading in local development
]
: [{ directive: "upgrade-insecure-requests", values: [] }]; // Upgrade all requests to HTTPS on production

const contentSecurityPolicyDirectives: ContentSecurityPolicyDirective[] = [
...siteContentSecurityPolicyDirectives,
...environmentDependentContentSecurityPolicyDirectives,
];

const contentSecurityPolicy = contentSecurityPolicyDirectives
.map((directive) => `${directive.directive} ${directive.values.join(" ")}`)
.join("; ");
response.headers.set("Content-Security-Policy", contentSecurityPolicy);
}

0 comments on commit 96ba580

Please sign in to comment.