From 97e7ebe9aa422bdc640ef4fb1fe7511327eb4f1a Mon Sep 17 00:00:00 2001 From: suphicakir Date: Thu, 5 Nov 2026 02:02:00 +0300 Subject: [PATCH] =?UTF-8?q?feat(security):=20CSP=20ve=20g=C3=BCvenlik=20ba?= =?UTF-8?q?=C5=9Fl=C4=B1klar=C4=B1,=20health=20DB=20ping?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- next.config.ts | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/next.config.ts b/next.config.ts index d80125d..8e8b26e 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,5 +1,47 @@ import type { NextConfig } from "next"; +const isDev = process.env.NODE_ENV === "development"; + +/** + * Content-Security-Policy (nonce'suz): Cache Components'in statik kabuğu ile uyumlu. + * 'unsafe-inline' script: Next.js'in satır içi hydration verisi ve next-themes'in tema betiği için. + * Grafikler (Recharts, SVG) ve carousel (Embla) ek kaynak gerektirmez; ek dosyalar + * kendi origin'imizden (/api/files/...) ve blob: önizlemelerle servis edilir. + */ +const csp = [ + "default-src 'self'", + `script-src 'self' 'unsafe-inline'${isDev ? " 'unsafe-eval'" : ""}`, + "style-src 'self' 'unsafe-inline'", + "img-src 'self' blob: data:", + "font-src 'self'", + "connect-src 'self'", + "media-src 'self' blob:", + "worker-src 'self' blob:", + "manifest-src 'self'", + "object-src 'none'", + "base-uri 'self'", + "form-action 'self'", + "frame-ancestors 'none'", + ...(isDev ? [] : ["upgrade-insecure-requests"]), +].join("; "); + +const securityHeaders = [ + { key: "Content-Security-Policy", value: csp }, + { key: "X-Content-Type-Options", value: "nosniff" }, + { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" }, + { key: "X-Frame-Options", value: "DENY" }, + { key: "Cross-Origin-Opener-Policy", value: "same-origin" }, + // Kamera: Faz 6'da fiş fotoğrafı için yalnızca kendi origin'imiz. + { + key: "Permissions-Policy", + value: "camera=(self), microphone=(), geolocation=(), payment=(), usb=()", + }, + ...(isDev + ? [] + : // includeSubDomains/preload bilinçli olarak yok: ta1sph.website'in diğer alt alanlarını bağlamasın. + [{ key: "Strict-Transport-Security", value: "max-age=31536000" }]), +]; + const nextConfig: NextConfig = { // Docker imajı için yalnızca gerekli dosyaları .next/standalone altına kopyala. output: "standalone", @@ -17,6 +59,9 @@ const nextConfig: NextConfig = { }, }, }, + async headers() { + return [{ source: "/:path*", headers: securityHeaders }]; + }, }; export default nextConfig;