import { NextResponse, type NextRequest } from "next/server"; import { isSameOrigin } from "@/lib/http"; /** * Läuft vor jeder Anfrage: setzt Schutzheader und weist schreibende Zugriffe * von fremden Seiten ab. * * Heißt `proxy.ts`, weil Next.js die Datei `middleware.ts` in Version 16 * umbenannt hat — siehe node_modules/next/dist/docs/01-app/03-api-reference/ * 03-file-conventions/proxy.md. * * ## Warum eine Origin-Prüfung, obwohl der Cookie `SameSite=Lax` ist * * Das OWASP-Merkblatt zu CSRF sagt ausdrücklich, dass `SameSite` allein nicht * genügt: Es wirkt auf der Ebene der registrierbaren Domain, nicht des * Ursprungs, und bei `Lax` gehen Cookies bei einfachen Navigationen weiterhin * mit. Der Upload-Endpunkt nimmt zudem `multipart/form-data` entgegen — das * kann ein HTML-Formular von einer fremden Seite abschicken. * * Fehlt der `Origin`-Header ganz, wird durchgelassen: Browser setzen ihn bei * fremden Zugriffen immer, Skripte und Kommandozeilenwerkzeuge oft gar nicht. * Ein Abweisen träfe also nur die Falschen. */ const SCHREIBEND = new Set(["POST", "PUT", "PATCH", "DELETE"]); /** * Woher eingebettete Videos kommen dürfen. * * Der Video-Typ bettet YouTube und Vimeo ein — beide brauchen einen eigenen * Eintrag, sonst bliebe der Rahmen nach dem Klick leer. Mehr steht hier * nicht: Was nicht eingebettet wird, gehört auch nicht in die Liste. */ const VIDEO_QUELLEN = [ "https://www.youtube-nocookie.com", "https://www.youtube.com", "https://player.vimeo.com", ].join(" "); /** * Die Content-Security-Policy dieser Anfrage. * * Skripte laufen nur mit dem Nonce dieser einen Anfrage oder weil ein Skript * sie geladen hat, das selbst eines hatte (`strict-dynamic`). Ein Skript, * das über eine Lücke in die Seite gerät, hat keines — und läuft nicht. * * **Warum `style-src` weiter `unsafe-inline` erlaubt:** Ein Nonce wirkt nur * auf `