feat(csp): nonce-based script-src replaces unsafe-inline + lazy service bearer #112

Merged
KnallerKalle merged 6 commits from feat/csp-nonce-hardening into dev 2026-08-18 17:49:42 +00:00
KnallerKalle commented 2026-08-18 17:23:23 +00:00 (Migrated from github.com)

Plan

Das letzte offene script-src 'unsafe-inline' schließen (Security-Audit-Follow-up): per-Request-Nonce statt globaler Inline-Freigabe. Nebenbei: PR-#85-Review-P2 beheben (Session-Mint bei jedem Cache-Hit).

Outcome

  • src/lib/csp.ts — pure CSP-Builder: script-src 'self' 'nonce-<random>' 'unsafe-eval' (kein 'unsafe-inline' mehr). Injizierte Inline-<script>-Tags ohne Nonce werden browser-seitig geblockt.
  • src/middleware.ts — mint pro Response eine frische Nonce (crypto.randomUUID), setzt Request-CSP-Header (damit Next.js seine Hydration-Bootstrap-Scripts automatisch mit der Nonce stampft — live per curl bewiesen: nonce="…"-Attribute auf den _next-Script-Tags) + Response-CSP. Locale-Redirect (/ → /de, 307) trägt die Policy. /api/*-CORS-Vertrag (Tauri Remote-Auth) unverändert.
  • src/lib/tts-synth.ts + public-audio-route.ts — bearer jetzt string | (() => string); die Route übergibt eine Minting-Thunk → Service-Session entsteht nur noch bei echten Cache-Misses. Der heiße 17 ms-Cache-Hit-Pfad schreibt keine Session-Zeile + Store-Persist mehr (P2: Write-Amplification).
  • next.config.js — Kommentar klargestellt: die dortige CSP ist nur noch Fallback für middleware-ferne Pfade.

Impact on release goals

  • Roadmap „CSP nonce-based script-src hardening (follow-up)" [ ] → [~].
  • XSS: die häufigste Payload-Klasse (injizierte Inline-Scripts) ist jetzt browser-seitig geblockt, nicht nur per Input-Sanitising.
  • Blackbox-Suite +7 Checks (25/25a–e) → 104; Unit-Suite 410/410 (398 + 9 CSP + 2 lazy-bearer + 1 Guard).

Blackbox

  • python3 scripts/blackbox_test.py --target testing → nach Merge (Test-25-Statuszeile wird dort grün, prod-build rendert /de/auth/login 200)
  • Result lokal (--base http://localhost:3000, dev-server ohne Backend): 70/86 grün; alle 7 neuen CSP-Checks grün (Nonce-Uniqueness über 2 Requests, kein unsafe-inline, Redirect-CSP, Baseline-Direktiven intakt). Die 16 Roten sind die dokumentierte Umgebungs-Baseline (15 identisch mit origin/dev-Vergleich + Test-25-Statuszeile env-bedingt: dev-mode-SSR-500).
  • Live-curl-Beweise: 2 Requests → 2 verschiedene Noncen; nonce=-Attribute auf Next-Bootstrap-Scripts (App blockt sich nicht selbst); 307 mit Policy.

Six-perspectives check

  • Product: kein Dark Pattern; reine Sicherheitshärtung
  • Engineering: minimaler Diff, TEST-FIRST (RED→GREEN für beide Changes), tsc clean, 410/410
  • Psychology: neutral, kein Verhaltensdrang
  • Biomechanics: n/a (keine Bewegungs-Cues berührt)
  • Anatomy: n/a
  • Feldenkrais: keine Lektionsinhalte berührt

Risk

  • Größtes Risiko einer Nonce-CSP: die eigene App blockt ihre Scripts. Entkräftet durch live-curl (Next stampft nonce-Attribute; keine erkennbaren Violations; lokale 500er = bekanntes dev-mode-useSession-Baseline-Problem, identisch auf dev).
  • 'unsafe-eval' verbleibt bewusst (eigener dokumentierter Follow-up — kein stiller Rollback).
  • Redirect-/CORS-Pfade per Unit-Test verriegelt (4/4 grün).

Checklist

  • Branch von latest dev (0bd51a8)
  • Conventional Commits (test: → feat: → test: → fix: → test:/docs:)
  • Patchlog-Eintrag angehängt
  • Roadmap-Status aktualisiert
  • Keine Secrets / keine Binaries

This PR was created by an AI agent (OpenHands) on behalf of the user.

## Plan Das letzte offene `script-src 'unsafe-inline'` schließen (Security-Audit-Follow-up): per-Request-Nonce statt globaler Inline-Freigabe. Nebenbei: PR-#85-Review-P2 beheben (Session-Mint bei jedem Cache-Hit). ## Outcome - `src/lib/csp.ts` — pure CSP-Builder: `script-src 'self' 'nonce-<random>' 'unsafe-eval'` (kein `'unsafe-inline'` mehr). Injizierte Inline-`<script>`-Tags ohne Nonce werden browser-seitig geblockt. - `src/middleware.ts` — mint pro Response eine frische Nonce (`crypto.randomUUID`), setzt Request-CSP-Header (damit Next.js seine Hydration-Bootstrap-Scripts automatisch mit der Nonce stampft — live per curl bewiesen: `nonce="…"`-Attribute auf den `_next`-Script-Tags) + Response-CSP. Locale-Redirect (/ → /de, 307) trägt die Policy. `/api/*`-CORS-Vertrag (Tauri Remote-Auth) unverändert. - `src/lib/tts-synth.ts` + `public-audio-route.ts` — `bearer` jetzt `string | (() => string)`; die Route übergibt eine Minting-Thunk → Service-Session entsteht **nur noch bei echten Cache-Misses**. Der heiße 17 ms-Cache-Hit-Pfad schreibt keine Session-Zeile + Store-Persist mehr (P2: Write-Amplification). - `next.config.js` — Kommentar klargestellt: die dortige CSP ist nur noch Fallback für middleware-ferne Pfade. ## Impact on release goals - Roadmap „CSP nonce-based script-src hardening (follow-up)" `[ ]` → `[~]`. - XSS: die häufigste Payload-Klasse (injizierte Inline-Scripts) ist jetzt **browser-seitig** geblockt, nicht nur per Input-Sanitising. - Blackbox-Suite +7 Checks (25/25a–e) → **104**; Unit-Suite **410/410** (398 + 9 CSP + 2 lazy-bearer + 1 Guard). ## Blackbox - [x] `python3 scripts/blackbox_test.py --target testing` → nach Merge (Test-25-Statuszeile wird dort grün, prod-build rendert /de/auth/login 200) - Result lokal (`--base http://localhost:3000`, dev-server ohne Backend): 70/86 grün; **alle 7 neuen CSP-Checks grün** (Nonce-Uniqueness über 2 Requests, kein unsafe-inline, Redirect-CSP, Baseline-Direktiven intakt). Die 16 Roten sind die dokumentierte Umgebungs-Baseline (15 identisch mit origin/dev-Vergleich + Test-25-Statuszeile env-bedingt: dev-mode-SSR-500). - Live-curl-Beweise: 2 Requests → 2 verschiedene Noncen; `nonce=`-Attribute auf Next-Bootstrap-Scripts (App blockt sich nicht selbst); 307 mit Policy. ## Six-perspectives check - [x] Product: kein Dark Pattern; reine Sicherheitshärtung - [x] Engineering: minimaler Diff, TEST-FIRST (RED→GREEN für beide Changes), tsc clean, 410/410 - [x] Psychology: neutral, kein Verhaltensdrang - [x] Biomechanics: n/a (keine Bewegungs-Cues berührt) - [x] Anatomy: n/a - [x] Feldenkrais: keine Lektionsinhalte berührt ## Risk - Größtes Risiko einer Nonce-CSP: die eigene App blockt ihre Scripts. Entkräftet durch live-curl (Next stampft nonce-Attribute; keine erkennbaren Violations; lokale 500er = bekanntes dev-mode-useSession-Baseline-Problem, identisch auf dev). - `'unsafe-eval'` verbleibt **bewusst** (eigener dokumentierter Follow-up — kein stiller Rollback). - Redirect-/CORS-Pfade per Unit-Test verriegelt (4/4 grün). ## Checklist - [x] Branch von latest dev (0bd51a8) - [x] Conventional Commits (test: → feat: → test: → fix: → test:/docs:) - [x] Patchlog-Eintrag angehängt - [x] Roadmap-Status aktualisiert - [x] Keine Secrets / keine Binaries _This PR was created by an AI agent (OpenHands) on behalf of the user._
KnallerKalle commented 2026-08-18 17:49:33 +00:00 (Migrated from github.com)

Verdict: Approve — P0–P3 keine Findings (self-review, iteration-loop Phase 8)

Scope des Reviews: src/middleware.ts, src/lib/csp.ts, src/lib/tts-synth.ts, src/lib/public-audio-route.ts, next.config.js, scripts/blackbox_test.py (Test 25), 3 Test-Dateien.

Geprüft:

  • CSP-Builder überträgt alle 12 Direktiven 1:1 aus next.config.js — einzig script-src verliert 'unsafe-inline' und gewinnt 'nonce-<random>'. Kein stilles Direktiven-Drop.
  • Nonce-Weitergabe an Next.js über Request-Header (content-security-policy + x-nonce) — der dokumentierte Weg; live per curl bewiesen: nonce="…"-Attribute auf den _next-Bootstrap-Script-Tags, zwei Requests → zwei Noncen. Die App blockt sich nicht selbst.
  • CORS-Vertrag /api/* (OPTIONS 204, ACAO *) unverändert — per Unit-Test verriegelt (Tauri Remote-Auth regressionsfrei).
  • Lazy-Bearer: Thunk wird erst im Backend-Pfad aufgelöst; String-Bearer (authentifizierter POST) unverändert. Cache-Hit schreibt keine Session mehr (RED→GREEN bewiesen).
  • Tauri-CI-Falle (no-op middleware ohne default-Export beim Typecheck) gefixt und in BEIDEN Zuständen tsc-clean verifiziert — die Fehlerklasse aus dem tauri-export-imports-Guard hiermit indirekt erweitert abgesichert.
  • 'unsafe-eval' verbleibt bewusst und ist als eigener Follow-up dokumentiert (kein stiller Rollback des Audit-Befehls).

Blackbox: lokal 70/86 (16 Rot = dokumentierte Umgebungs-Baseline: kein FastAPI, leerer Store, dev-mode-SSR-500 — identisch mit origin/dev-Vergleichslauf); alle 7 neuen CSP-Checks grün. Autoritativ: testing-Verifikation direkt nach Merge.

Roadmap impact: „CSP nonce-based script-src hardening (follow-up)" [ ] → [x] nach testing-Verifikation.

Hinweis: Review erstellt von einem AI-Agent (OpenHands) im Auftrag des Users.

**Verdict: Approve — P0–P3 keine Findings** (self-review, iteration-loop Phase 8) Scope des Reviews: `src/middleware.ts`, `src/lib/csp.ts`, `src/lib/tts-synth.ts`, `src/lib/public-audio-route.ts`, `next.config.js`, `scripts/blackbox_test.py` (Test 25), 3 Test-Dateien. **Geprüft:** - CSP-Builder überträgt alle 12 Direktiven 1:1 aus next.config.js — einzig `script-src` verliert `'unsafe-inline'` und gewinnt `'nonce-<random>'`. Kein stilles Direktiven-Drop. - Nonce-Weitergabe an Next.js über Request-Header (`content-security-policy` + `x-nonce`) — der dokumentierte Weg; live per curl bewiesen: `nonce="…"`-Attribute auf den `_next`-Bootstrap-Script-Tags, zwei Requests → zwei Noncen. Die App blockt sich nicht selbst. - CORS-Vertrag `/api/*` (OPTIONS 204, ACAO `*`) unverändert — per Unit-Test verriegelt (Tauri Remote-Auth regressionsfrei). - Lazy-Bearer: Thunk wird erst im Backend-Pfad aufgelöst; String-Bearer (authentifizierter POST) unverändert. Cache-Hit schreibt keine Session mehr (RED→GREEN bewiesen). - Tauri-CI-Falle (no-op middleware ohne default-Export beim Typecheck) gefixt und in BEIDEN Zuständen tsc-clean verifiziert — die Fehlerklasse aus dem tauri-export-imports-Guard hiermit indirekt erweitert abgesichert. - `'unsafe-eval'` verbleibt bewusst und ist als eigener Follow-up dokumentiert (kein stiller Rollback des Audit-Befehls). **Blackbox:** lokal 70/86 (16 Rot = dokumentierte Umgebungs-Baseline: kein FastAPI, leerer Store, dev-mode-SSR-500 — identisch mit origin/dev-Vergleichslauf); **alle 7 neuen CSP-Checks grün**. Autoritativ: testing-Verifikation direkt nach Merge. **Roadmap impact:** „CSP nonce-based script-src hardening (follow-up)" `[ ]` → `[x]` nach testing-Verifikation. _Hinweis: Review erstellt von einem AI-Agent (OpenHands) im Auftrag des Users._
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Kalle/ATM!112
No description provided.