From 7a25dce936a0bd699d2287ba82d00634e2ee8631 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Wed, 30 Apr 2025 09:14:11 +0200 Subject: [PATCH 1/9] fix: override csp for allowed iframe --- apps/login/next.config.mjs | 5 ++- .../app/(login)/authenticator/set/page.tsx | 11 ++--- apps/login/src/app/login/route.ts | 44 +++++++++++++++---- apps/login/src/lib/csp.ts | 2 + apps/login/src/lib/zitadel.ts | 15 +++++++ apps/login/src/middleware.ts | 18 ++++++++ 6 files changed, 76 insertions(+), 19 deletions(-) create mode 100644 apps/login/src/lib/csp.ts diff --git a/apps/login/next.config.mjs b/apps/login/next.config.mjs index 00fa1e19c4..2795854114 100755 --- a/apps/login/next.config.mjs +++ b/apps/login/next.config.mjs @@ -1,4 +1,5 @@ import createNextIntlPlugin from "next-intl/plugin"; +import { DEFAULT_CSP } from "./src/lib/csp"; const withNextIntl = createNextIntlPlugin(); @@ -29,9 +30,9 @@ const secureHeaders = [ // script-src va.vercel-scripts.com for analytics/vercel scripts { key: "Content-Security-Policy", - value: - "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://va.vercel-scripts.com; connect-src 'self'; child-src; style-src 'self' 'unsafe-inline'; font-src 'self'; object-src 'none'; img-src 'self' https://vercel.com;", + value: `${DEFAULT_CSP} frame-ancestors 'none'`, }, + { key: "X-Frame-Options", value: "deny" }, ]; const imageRemotePatterns = [ diff --git a/apps/login/src/app/(login)/authenticator/set/page.tsx b/apps/login/src/app/(login)/authenticator/set/page.tsx index 8240023c2d..8904eff963 100644 --- a/apps/login/src/app/(login)/authenticator/set/page.tsx +++ b/apps/login/src/app/(login)/authenticator/set/page.tsx @@ -33,8 +33,8 @@ export default async function Page(props: { const { serviceUrl } = getServiceUrlFromHeaders(_headers); const sessionWithData = sessionId - ? await loadSessionById(serviceUrl, sessionId, organization) - : await loadSessionByLoginname(serviceUrl, loginName, organization); + ? await loadSessionById(sessionId, organization) + : await loadSessionByLoginname(loginName, organization); async function getAuthMethodsAndUser( serviceUrl: string, @@ -67,7 +67,6 @@ export default async function Page(props: { } async function loadSessionByLoginname( - host: string, loginName?: string, organization?: string, ) { @@ -82,11 +81,7 @@ export default async function Page(props: { }); } - async function loadSessionById( - host: string, - sessionId: string, - organization?: string, - ) { + async function loadSessionById(sessionId: string, organization?: string) { const recent = await getSessionCookieById({ sessionId, organization }); return getSession({ serviceUrl, diff --git a/apps/login/src/app/login/route.ts b/apps/login/src/app/login/route.ts index e3834e5a27..b3da6f863e 100644 --- a/apps/login/src/app/login/route.ts +++ b/apps/login/src/app/login/route.ts @@ -1,4 +1,5 @@ import { getAllSessions } from "@/lib/cookies"; +import { DEFAULT_CSP } from "@/lib/csp"; import { idpTypeToSlug } from "@/lib/idp"; import { loginWithOIDCandSession } from "@/lib/oidc"; import { loginWithSAMLandSession } from "@/lib/saml"; @@ -12,6 +13,7 @@ import { getAuthRequest, getOrgsByDomain, getSAMLRequest, + getSecuritySettings, listSessions, startIdentityProviderFlow, } from "@/lib/zitadel"; @@ -293,17 +295,32 @@ export async function GET(request: NextRequest) { * This means that the user should not be prompted to enter their password again. * Instead, the server attempts to silently authenticate the user using an existing session or other authentication mechanisms that do not require user interaction **/ + const securitySettings = await getSecuritySettings({ + serviceUrl, + }); + const selectedSession = await findValidSession({ serviceUrl, sessions, authRequest, }); - if (!selectedSession || !selectedSession.id) { - return NextResponse.json( - { error: "No active session found" }, - { status: 400 }, + const noSessionResponse = NextResponse.json( + { error: "No active session found" }, + { status: 400 }, + ); + + if (securitySettings?.embeddedIframe?.enabled) { + securitySettings.embeddedIframe.allowedOrigins; + noSessionResponse.headers.set( + "Content-Security-Policy", + `${DEFAULT_CSP} frame-ancestors ${securitySettings.embeddedIframe.allowedOrigins.join(" ")};`, ); + noSessionResponse.headers.delete("X-Frame-Options"); + } + + if (!selectedSession || !selectedSession.id) { + return noSessionResponse; } const cookie = sessionCookies.find( @@ -311,10 +328,7 @@ export async function GET(request: NextRequest) { ); if (!cookie || !cookie.id || !cookie.token) { - return NextResponse.json( - { error: "No active session found" }, - { status: 400 }, - ); + return noSessionResponse; } const session = { @@ -332,7 +346,19 @@ export async function GET(request: NextRequest) { }, }), }); - return NextResponse.redirect(callbackUrl); + + const callbackResponse = NextResponse.redirect(callbackUrl); + + if (securitySettings?.embeddedIframe?.enabled) { + securitySettings.embeddedIframe.allowedOrigins; + callbackResponse.headers.set( + "Content-Security-Policy", + `${DEFAULT_CSP} frame-ancestors ${securitySettings.embeddedIframe.allowedOrigins.join(" ")};`, + ); + callbackResponse.headers.delete("X-Frame-Options"); + } + + return callbackResponse; } else { // check for loginHint, userId hint and valid sessions let selectedSession = await findValidSession({ diff --git a/apps/login/src/lib/csp.ts b/apps/login/src/lib/csp.ts new file mode 100644 index 0000000000..5cc1e254f3 --- /dev/null +++ b/apps/login/src/lib/csp.ts @@ -0,0 +1,2 @@ +export const DEFAULT_CSP = + "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://va.vercel-scripts.com; connect-src 'self'; child-src; style-src 'self' 'unsafe-inline'; font-src 'self'; object-src 'none'; img-src 'self' https://vercel.com;"; diff --git a/apps/login/src/lib/zitadel.ts b/apps/login/src/lib/zitadel.ts index 0511eaaf0d..a5abc0dcb1 100644 --- a/apps/login/src/lib/zitadel.ts +++ b/apps/login/src/lib/zitadel.ts @@ -92,6 +92,21 @@ export async function getLoginSettings({ return useCache ? cacheWrapper(callback) : callback; } +export async function getSecuritySettings({ + serviceUrl, +}: { + serviceUrl: string; +}) { + const settingsService: Client = + await createServiceForHost(SettingsService, serviceUrl); + + const callback = settingsService + .getSecuritySettings({}) + .then((resp) => (resp.settings ? resp.settings : undefined)); + + return useCache ? cacheWrapper(callback) : callback; +} + export async function getLockoutSettings({ serviceUrl, orgId, diff --git a/apps/login/src/middleware.ts b/apps/login/src/middleware.ts index 8d4080cddf..0572fe43b6 100644 --- a/apps/login/src/middleware.ts +++ b/apps/login/src/middleware.ts @@ -1,6 +1,8 @@ import { headers } from "next/headers"; import { NextRequest, NextResponse } from "next/server"; +import { DEFAULT_CSP } from "./lib/csp"; import { getServiceUrlFromHeaders } from "./lib/service"; +import { getSecuritySettings } from "./lib/zitadel"; export const config = { matcher: [ @@ -22,6 +24,8 @@ export async function middleware(request: NextRequest) { const { serviceUrl } = getServiceUrlFromHeaders(_headers); + const securitySettings = await getSecuritySettings({ serviceUrl }); + const instanceHost = `${serviceUrl}` .replace("https://", "") .replace("http://", ""); @@ -39,6 +43,20 @@ export async function middleware(request: NextRequest) { responseHeaders.set("Access-Control-Allow-Origin", "*"); responseHeaders.set("Access-Control-Allow-Headers", "*"); + responseHeaders.set( + "Content-Security-Policy", + `${DEFAULT_CSP} frame-ancestors 'none'`, + ); + + if (securitySettings?.embeddedIframe?.enabled) { + securitySettings.embeddedIframe.allowedOrigins; + responseHeaders.set( + "Content-Security-Policy", + `${DEFAULT_CSP} frame-ancestors ${securitySettings.embeddedIframe.allowedOrigins.join(" ")};`, + ); + responseHeaders.delete("X-Frame-Options"); + } + request.nextUrl.href = `${serviceUrl}${request.nextUrl.pathname}${request.nextUrl.search}`; return NextResponse.rewrite(request.nextUrl, { request: { From 231ecdc5c54f3872cbcc4e1eb270943d224010cd Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Wed, 30 Apr 2025 09:18:01 +0200 Subject: [PATCH 2/9] change import --- apps/login/next.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/login/next.config.mjs b/apps/login/next.config.mjs index 2795854114..7fb0f5b65d 100755 --- a/apps/login/next.config.mjs +++ b/apps/login/next.config.mjs @@ -1,5 +1,5 @@ import createNextIntlPlugin from "next-intl/plugin"; -import { DEFAULT_CSP } from "./src/lib/csp"; +import { DEFAULT_CSP } from "src/lib/csp"; const withNextIntl = createNextIntlPlugin(); From a31c17f5fa4c424bab251d92f2db869617c9e20e Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Wed, 30 Apr 2025 09:20:26 +0200 Subject: [PATCH 3/9] @ ns --- apps/login/next.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/login/next.config.mjs b/apps/login/next.config.mjs index 7fb0f5b65d..0820c0c555 100755 --- a/apps/login/next.config.mjs +++ b/apps/login/next.config.mjs @@ -1,5 +1,5 @@ import createNextIntlPlugin from "next-intl/plugin"; -import { DEFAULT_CSP } from "src/lib/csp"; +import { DEFAULT_CSP } from "@/lib/csp"; const withNextIntl = createNextIntlPlugin(); From a690b254c4858e3419f14968a621936ecc7cebed Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Wed, 30 Apr 2025 09:23:56 +0200 Subject: [PATCH 4/9] import --- apps/login/next.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/login/next.config.mjs b/apps/login/next.config.mjs index 0820c0c555..2795854114 100755 --- a/apps/login/next.config.mjs +++ b/apps/login/next.config.mjs @@ -1,5 +1,5 @@ import createNextIntlPlugin from "next-intl/plugin"; -import { DEFAULT_CSP } from "@/lib/csp"; +import { DEFAULT_CSP } from "./src/lib/csp"; const withNextIntl = createNextIntlPlugin(); From 77e9f6f2e90505236a2dbdd9125f6ba8aa06ce6e Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Wed, 30 Apr 2025 09:41:00 +0200 Subject: [PATCH 5/9] override cookie sameSite settings --- apps/login/src/lib/cookies.ts | 60 ++++++++++++++------- apps/login/src/lib/server/cookie.ts | 79 ++++++++++++++++++---------- apps/login/src/lib/server/session.ts | 11 +++- 3 files changed, 99 insertions(+), 51 deletions(-) diff --git a/apps/login/src/lib/cookies.ts b/apps/login/src/lib/cookies.ts index cf762b904f..76f5580a16 100644 --- a/apps/login/src/lib/cookies.ts +++ b/apps/login/src/lib/cookies.ts @@ -20,7 +20,10 @@ export type Cookie = { type SessionCookie = Cookie & T; -async function setSessionHttpOnlyCookie(sessions: SessionCookie[]) { +async function setSessionHttpOnlyCookie( + sessions: SessionCookie[], + sameSite: boolean | "lax" | "strict" | "none" = true, +) { const cookiesList = await cookies(); return cookiesList.set({ @@ -28,6 +31,7 @@ async function setSessionHttpOnlyCookie(sessions: SessionCookie[]) { value: JSON.stringify(sessions), httpOnly: true, path: "/", + sameSite, }); } @@ -42,10 +46,15 @@ export async function setLanguageCookie(language: string) { }); } -export async function addSessionToCookie( - session: SessionCookie, - cleanup: boolean = false, -): Promise { +export async function addSessionToCookie({ + session, + cleanup, + sameSite, +}: { + session: SessionCookie; + cleanup?: boolean; + sameSite?: boolean | "lax" | "strict" | "none" | undefined; +}): Promise { const cookiesList = await cookies(); const stringifiedCookie = cookiesList.get("sessions"); @@ -79,17 +88,23 @@ export async function addSessionToCookie( ? timestampDate(timestampFromMs(Number(session.expirationTs))) > now : true, ); - return setSessionHttpOnlyCookie(filteredSessions); + return setSessionHttpOnlyCookie(filteredSessions, sameSite); } else { - return setSessionHttpOnlyCookie(currentSessions); + return setSessionHttpOnlyCookie(currentSessions, sameSite); } } -export async function updateSessionCookie( - id: string, - session: SessionCookie, - cleanup: boolean = false, -): Promise { +export async function updateSessionCookie({ + id, + session, + cleanup, + sameSite, +}: { + id: string; + session: SessionCookie; + cleanup?: boolean; + sameSite?: boolean | "lax" | "strict" | "none" | undefined; +}): Promise { const cookiesList = await cookies(); const stringifiedCookie = cookiesList.get("sessions"); @@ -108,19 +123,24 @@ export async function updateSessionCookie( ? timestampDate(timestampFromMs(Number(session.expirationTs))) > now : true, ); - return setSessionHttpOnlyCookie(filteredSessions); + return setSessionHttpOnlyCookie(filteredSessions, sameSite); } else { - return setSessionHttpOnlyCookie(sessions); + return setSessionHttpOnlyCookie(sessions, sameSite); } } else { throw "updateSessionCookie: session id now found"; } } -export async function removeSessionFromCookie( - session: SessionCookie, - cleanup: boolean = false, -): Promise { +export async function removeSessionFromCookie({ + session, + cleanup, + sameSite, +}: { + session: SessionCookie; + cleanup?: boolean; + sameSite?: boolean | "lax" | "strict" | "none" | undefined; +}): Promise { const cookiesList = await cookies(); const stringifiedCookie = cookiesList.get("sessions"); @@ -136,9 +156,9 @@ export async function removeSessionFromCookie( ? timestampDate(timestampFromMs(Number(session.expirationTs))) > now : true, ); - return setSessionHttpOnlyCookie(filteredSessions); + return setSessionHttpOnlyCookie(filteredSessions, sameSite); } else { - return setSessionHttpOnlyCookie(reducedSessions); + return setSessionHttpOnlyCookie(reducedSessions, sameSite); } } diff --git a/apps/login/src/lib/server/cookie.ts b/apps/login/src/lib/server/cookie.ts index d54a4047b1..7cc86e9337 100644 --- a/apps/login/src/lib/server/cookie.ts +++ b/apps/login/src/lib/server/cookie.ts @@ -4,6 +4,7 @@ import { addSessionToCookie, updateSessionCookie } from "@/lib/cookies"; import { createSessionForUserIdAndIdpIntent, createSessionFromChecks, + getSecuritySettings, getSession, setSession, } from "@/lib/zitadel"; @@ -65,7 +66,7 @@ export async function createSessionAndUpdateCookie(command: { serviceUrl, sessionId: createdSession.sessionId, sessionToken: createdSession.sessionToken, - }).then((response) => { + }).then(async (response) => { if (response?.session && response.session?.factors?.user?.loginName) { const sessionCookie: CustomCookieData = { id: createdSession.sessionId, @@ -91,9 +92,14 @@ export async function createSessionAndUpdateCookie(command: { response.session.factors.user.organizationId; } - return addSessionToCookie(sessionCookie).then(() => { - return response.session as Session; - }); + const securitySettings = await getSecuritySettings({ serviceUrl }); + const sameSite = securitySettings?.embeddedIframe?.enabled + ? "none" + : true; + + await addSessionToCookie({ session: sessionCookie, sameSite }); + + return response.session as Session; } else { throw "could not get session or session does not have loginName"; } @@ -167,7 +173,10 @@ export async function createSessionForIdpAndUpdateCookie( sessionCookie.organization = session.factors.user.organizationId; } - return addSessionToCookie(sessionCookie).then(() => { + const securitySettings = await getSecuritySettings({ serviceUrl }); + const sameSite = securitySettings?.embeddedIframe?.enabled ? "none" : true; + + return addSessionToCookie({ session: sessionCookie, sameSite }).then(() => { return session as Session; }); } @@ -217,32 +226,44 @@ export async function setSessionAndUpdateCookie( serviceUrl, sessionId: sessionCookie.id, sessionToken: sessionCookie.token, - }).then((response) => { - if (response?.session && response.session.factors?.user?.loginName) { - const { session } = response; - const newCookie: CustomCookieData = { - id: sessionCookie.id, - token: updatedSession.sessionToken, - creationTs: sessionCookie.creationTs, - expirationTs: sessionCookie.expirationTs, - // just overwrite the changeDate with the new one - changeTs: updatedSession.details?.changeDate - ? `${timestampMs(updatedSession.details.changeDate)}` - : "", - loginName: session.factors?.user?.loginName ?? "", - organization: session.factors?.user?.organizationId ?? "", - }; - - if (sessionCookie.requestId) { - newCookie.requestId = sessionCookie.requestId; - } - - return updateSessionCookie(sessionCookie.id, newCookie).then(() => { - return { challenges: updatedSession.challenges, ...session }; - }); - } else { + }).then(async (response) => { + if ( + !response?.session || + !response.session.factors?.user?.loginName + ) { throw "could not get session or session does not have loginName"; } + + const { session } = response; + const newCookie: CustomCookieData = { + id: sessionCookie.id, + token: updatedSession.sessionToken, + creationTs: sessionCookie.creationTs, + expirationTs: sessionCookie.expirationTs, + // just overwrite the changeDate with the new one + changeTs: updatedSession.details?.changeDate + ? `${timestampMs(updatedSession.details.changeDate)}` + : "", + loginName: session.factors?.user?.loginName ?? "", + organization: session.factors?.user?.organizationId ?? "", + }; + + if (sessionCookie.requestId) { + newCookie.requestId = sessionCookie.requestId; + } + + const securitySettings = await getSecuritySettings({ serviceUrl }); + const sameSite = securitySettings?.embeddedIframe?.enabled + ? "none" + : true; + + return updateSessionCookie({ + id: sessionCookie.id, + session: newCookie, + sameSite, + }).then(() => { + return { challenges: updatedSession.challenges, ...session }; + }); }); } else { throw "Session not be set"; diff --git a/apps/login/src/lib/server/session.ts b/apps/login/src/lib/server/session.ts index 66688bf415..3ff3d14017 100644 --- a/apps/login/src/lib/server/session.ts +++ b/apps/login/src/lib/server/session.ts @@ -4,6 +4,7 @@ import { setSessionAndUpdateCookie } from "@/lib/server/cookie"; import { deleteSession, getLoginSettings, + getSecuritySettings, humanMFAInitSkipped, listAuthenticationMethodTypes, } from "@/lib/zitadel"; @@ -209,8 +210,11 @@ export async function clearSession(options: ClearSessionOptions) { sessionToken: session.token, }); + const securitySettings = await getSecuritySettings({ serviceUrl }); + const sameSite = securitySettings?.embeddedIframe?.enabled ? "none" : true; + if (deletedSession) { - return removeSessionFromCookie(session); + return removeSessionFromCookie({ session, sameSite }); } } @@ -230,9 +234,12 @@ export async function cleanupSession({ sessionId }: CleanupSessionCommand) { sessionToken: sessionCookie.token, }); + const securitySettings = await getSecuritySettings({ serviceUrl }); + const sameSite = securitySettings?.embeddedIframe?.enabled ? "none" : true; + if (!deleteResponse) { throw new Error("Could not delete session"); } - return removeSessionFromCookie(sessionCookie); + return removeSessionFromCookie({ session: sessionCookie, sameSite }); } From 43dff470bd41ef797a3726368b421057d2f06ef8 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Wed, 30 Apr 2025 09:47:51 +0200 Subject: [PATCH 6/9] csp import --- apps/login/constants/csp.js | 2 ++ apps/login/next.config.mjs | 2 +- apps/login/src/app/login/route.ts | 2 +- apps/login/src/lib/csp.ts | 2 -- apps/login/src/middleware.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) create mode 100644 apps/login/constants/csp.js delete mode 100644 apps/login/src/lib/csp.ts diff --git a/apps/login/constants/csp.js b/apps/login/constants/csp.js new file mode 100644 index 0000000000..21dc869a53 --- /dev/null +++ b/apps/login/constants/csp.js @@ -0,0 +1,2 @@ +export const DEFAULT_CSP = + "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://va.vercel-scripts.com; connect-src 'self'; child-src; style-src 'self' 'unsafe-inline'; font-src 'self'; object-src 'none'; img-src 'self' https://vercel.com;"; diff --git a/apps/login/next.config.mjs b/apps/login/next.config.mjs index 2795854114..edf5e54595 100755 --- a/apps/login/next.config.mjs +++ b/apps/login/next.config.mjs @@ -1,5 +1,5 @@ import createNextIntlPlugin from "next-intl/plugin"; -import { DEFAULT_CSP } from "./src/lib/csp"; +import { DEFAULT_CSP } from "./constants/csp.js"; const withNextIntl = createNextIntlPlugin(); diff --git a/apps/login/src/app/login/route.ts b/apps/login/src/app/login/route.ts index b3da6f863e..fb2f5e5f49 100644 --- a/apps/login/src/app/login/route.ts +++ b/apps/login/src/app/login/route.ts @@ -1,5 +1,4 @@ import { getAllSessions } from "@/lib/cookies"; -import { DEFAULT_CSP } from "@/lib/csp"; import { idpTypeToSlug } from "@/lib/idp"; import { loginWithOIDCandSession } from "@/lib/oidc"; import { loginWithSAMLandSession } from "@/lib/saml"; @@ -27,6 +26,7 @@ import { CreateResponseRequestSchema } from "@zitadel/proto/zitadel/saml/v2/saml import { Session } from "@zitadel/proto/zitadel/session/v2/session_pb"; import { headers } from "next/headers"; import { NextRequest, NextResponse } from "next/server"; +import { DEFAULT_CSP } from "../../../constants/csp"; export const dynamic = "force-dynamic"; export const revalidate = false; diff --git a/apps/login/src/lib/csp.ts b/apps/login/src/lib/csp.ts deleted file mode 100644 index 5cc1e254f3..0000000000 --- a/apps/login/src/lib/csp.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const DEFAULT_CSP = - "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://va.vercel-scripts.com; connect-src 'self'; child-src; style-src 'self' 'unsafe-inline'; font-src 'self'; object-src 'none'; img-src 'self' https://vercel.com;"; diff --git a/apps/login/src/middleware.ts b/apps/login/src/middleware.ts index 0572fe43b6..0621b2f5f2 100644 --- a/apps/login/src/middleware.ts +++ b/apps/login/src/middleware.ts @@ -1,6 +1,6 @@ import { headers } from "next/headers"; import { NextRequest, NextResponse } from "next/server"; -import { DEFAULT_CSP } from "./lib/csp"; +import { DEFAULT_CSP } from "../constants/csp"; import { getServiceUrlFromHeaders } from "./lib/service"; import { getSecuritySettings } from "./lib/zitadel"; From 0568aed6e0bfc443c53b139453036eae3f009c02 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Wed, 30 Apr 2025 09:52:03 +0200 Subject: [PATCH 7/9] lint --- apps/login/constants/csp.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/login/constants/csp.js b/apps/login/constants/csp.js index 21dc869a53..5cc1e254f3 100644 --- a/apps/login/constants/csp.js +++ b/apps/login/constants/csp.js @@ -1,2 +1,2 @@ export const DEFAULT_CSP = - "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://va.vercel-scripts.com; connect-src 'self'; child-src; style-src 'self' 'unsafe-inline'; font-src 'self'; object-src 'none'; img-src 'self' https://vercel.com;"; + "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://va.vercel-scripts.com; connect-src 'self'; child-src; style-src 'self' 'unsafe-inline'; font-src 'self'; object-src 'none'; img-src 'self' https://vercel.com;"; From a6cf9a6db688aa23875a706716de9e6ecae62a27 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Wed, 30 Apr 2025 09:58:29 +0200 Subject: [PATCH 8/9] empty security settings as default for integration tests --- .../initial-stubs/zitadel.settings.v2.SettingsService.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/login/mock/initial-stubs/zitadel.settings.v2.SettingsService.json b/apps/login/mock/initial-stubs/zitadel.settings.v2.SettingsService.json index 07e9980f9b..3da4ae999f 100644 --- a/apps/login/mock/initial-stubs/zitadel.settings.v2.SettingsService.json +++ b/apps/login/mock/initial-stubs/zitadel.settings.v2.SettingsService.json @@ -6,6 +6,13 @@ "data": {} } }, + { + "service": "zitadel.settings.v2.SettingsService", + "method": "GetSecuritySettings", + "out": { + "data": {} + } + }, { "service": "zitadel.settings.v2.SettingsService", "method": "GetLegalAndSupportSettings", From 449e632766c7cb7a8dd95bdafe2c318b7c530ed2 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Wed, 30 Apr 2025 10:05:24 +0200 Subject: [PATCH 9/9] remove fallback --- apps/login/src/middleware.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/login/src/middleware.ts b/apps/login/src/middleware.ts index 0621b2f5f2..6184bee182 100644 --- a/apps/login/src/middleware.ts +++ b/apps/login/src/middleware.ts @@ -43,11 +43,6 @@ export async function middleware(request: NextRequest) { responseHeaders.set("Access-Control-Allow-Origin", "*"); responseHeaders.set("Access-Control-Allow-Headers", "*"); - responseHeaders.set( - "Content-Security-Policy", - `${DEFAULT_CSP} frame-ancestors 'none'`, - ); - if (securitySettings?.embeddedIframe?.enabled) { securitySettings.embeddedIframe.allowedOrigins; responseHeaders.set(