/** * Content-Security-Policy – eine einzige Quelle der Wahrheit. * * Die Richtlinie erreicht den Renderer auf zwei Wegen, und beide gelten * gleichzeitig. Chromium wertet mehrere Richtlinien nebeneinander aus, jede * für sich; erlaubt bleibt nur, was allen genügt – die Schnittmenge. * * 1. als `` im Renderer-HTML * (eingesetzt beim Bau, siehe `cspPlugin` in `electron.vite.config.ts`), * 2. als HTTP-Kopf über `onHeadersReceived` im Main-Prozess * (siehe `cspHeaderSetzen` in `src/main/sicherheit.ts`). * * ## Warum es zwei Fassungen gibt * * Drei Direktiven ignoriert jeder Browser, wenn sie über ein ``-Element * kommen: `frame-ancestors`, `report-uri` und `sandbox`. Sie richten sich an * den einbettenden Kontext bzw. an den Ladevorgang selbst – beides steht fest, * bevor das HTML geparst ist. Chromium schreibt dann bei jedem Start einen * Konsolenfehler: „The Content Security Policy directive 'frame-ancestors' is * ignored when delivered via a element.“ * * Genau das tat dieses Programm, weil `frame-ancestors 'none'` in beiden * Fassungen stand. Eine Direktive, die dasteht und nicht gilt, ist schlimmer * als keine: Zwei Tests prüften ihren Wortlaut und meldeten grün. * * Die ``-Fassung lässt diese Direktiven deshalb weg ({@link NUR_IM_KOPF}). * Im Kopf bleiben sie stehen – dort gelten sie. * * ## Warum der Schutz dabei nicht verloren geht – nachgemessen * * Hier stand früher, der Kopf-Weg sei nur für den Vite-Dev-Server da und * `file://` hänge allein am ``-Element. Das stimmt nicht: * `onHeadersReceived` greift in Electron auch für `file://`-Antworten. * * Nachgemessen am gebauten Programm (`out/main/index.js`, Electron 43): Ein * absichtlich ausgelöster Verstoß gegen `img-src` meldete **zwei** * `securitypolicyviolation`-Ereignisse – eines mit dem Wortlaut der * Kopf-Fassung, eines mit dem der ``-Fassung. Der Kopf kommt also im * Renderer an, und mit ihm `frame-ancestors`. Dieselbe Messung führt * `e2e/anwendung.spec.ts` bei jedem Lauf im echten Fenster durch, damit die * Zusicherung nicht wieder zur Behauptung wird. * * ## Beide Fassungen dürfen sonst nicht auseinanderlaufen * * Wäre die Kopf-Fassung strenger als die ``-Fassung, bräche der * Dev-Modus unbemerkt an der Schnittmenge. `tests/sicherheit.test.ts` hält * deshalb fest: ``-Fassung == Kopf-Fassung ohne die Nur-Kopf-Direktiven, * Zeichen für Zeichen. */ export type CspModus = 'development' | 'production'; /** Über welchen Weg die Richtlinie ausgeliefert wird. */ export type CspZiel = 'meta' | 'kopf'; /** * Direktiven, die ausschließlich als HTTP-Kopf wirken. * * Über ein ``-Element werden sie ignoriert – mit Konsolenfehler. Wer * hier etwas ergänzt, nimmt es damit zugleich aus der ``-Fassung heraus. * Vollständig laut CSP Level 3: `frame-ancestors`, `report-uri`, `sandbox`. * Aufgeführt sind nur die, die diese Anwendung tatsächlich setzt. */ const NUR_IM_KOPF: readonly string[] = ['frame-ancestors']; /** * Im Produktionsbuild gilt eine strenge Richtlinie ohne `unsafe-*`. * Im Dev-Modus sind zusätzlich nötig: * - `'unsafe-inline'` für Skripte: Vite injiziert die React-Refresh-Präambel * als Inline-Skript in das HTML. * - `'unsafe-inline'` für Styles: HMR fügt `