Use Cases (Aktualisiert: 2.6.2026)

Web Security Headers mit Claude Code: CSP, Nonce, HSTS und sichere Einführung

Setze CSP, Nonces, HSTS, frame-ancestors und Security Headers mit Claude Code um.

Web Security Headers mit Claude Code: CSP, Nonce, HSTS und sichere Einführung

Web Security Headers wirken unscheinbar, aber sie steuern zentrale Sicherheitsentscheidungen im Browser. Sie legen fest, welche Skripte ausgeführt werden dürfen, ob ein Admin-Bereich in einem fremden iframe landen kann, wie viele Referrer-Daten an externe Seiten gehen und ob Funktionen wie Kamera, Mikrofon oder Geolocation verfügbar sind.

Claude Code ist für diese Aufgabe hilfreich, weil es das Repository lesen, Drittanbieter-Skripte finden, Framework-Konfigurationen ändern und Prüfkommandos erstellen kann. Gleichzeitig ist ein ungenauer Auftrag riskant. Wer nur „behebe die CSP-Fehler“ schreibt, bekommt leicht eine viel zu breite Policy wie script-src * 'unsafe-inline' 'unsafe-eval'. Die Fehler verschwinden, aber der Schutz verschwindet mit.

Der belastbare Ablauf ist: Ressourcen inventarisieren, Content-Security-Policy-Report-Only ausrollen, Reports auswerten, die Policy pro Route schärfen und erst dann erzwingen. Dieser Artikel behandelt CSP, Nonces, HSTS, X-Frame-Options, frame-ancestors, Referrer-Policy und Permissions-Policy mit Beispielen für Next.js, Astro, Express und Cloudflare Pages. Außerdem geht es um CSP Reports, Security Headers, CSP Evaluator und typische Konflikte mit Google Tag Manager, Google Analytics, AdSense, Bildern und CDNs. Für den sicheren Umgang mit Claude Code selbst passen Claude Code Security Best Practices und Security Audit mit Claude Code dazu.

Prüfe die Details immer gegen offizielle Quellen: MDN Content-Security-Policy, Next.js CSP guide, MDN Strict-Transport-Security, hstspreload.org, Cloudflare Pages Headers, Helmet, Google Tag Manager CSP und AdSense CSP.

Erst Inventar, dann Policy

Eine CSP sollte nicht mit einem kopierten Beispiel beginnen. Zuerst muss klar sein, was die Anwendung wirklich lädt.

Entwerfe Web Security Headers für dieses Repository.
Vorgaben:
- Liste zuerst externe Quellen für script, style, image, font, frame und connect.
- CSP startet im Report-Only-Modus.
- Vermeide * und dauerhaftes unsafe-inline.
- Erkläre bei Next.js-Nonces den Einfluss auf dynamisches Rendering und Caching.
- Prüfe Google Analytics, GTM, AdSense, Bild-CDNs und YouTube-iframes.
- Liefere Prüfungen mit curl, Security Headers und CSP Evaluator.

Die wichtigste Unterscheidung: frame-src regelt, welche iframes deine Seite laden darf. frame-ancestors regelt, wer deine Seite in einen iframe setzen darf. Analytics-Probleme liegen oft in connect-src, kaputte CDN-Bilder in img-src, und Clickjacking-Schutz in frame-ancestors.

HeaderStartpunktVorsicht
Content-Security-PolicyZuerst Content-Security-Policy-Report-OnlyNicht mit * oder permanentem unsafe-inline ausweichen
Strict-Transport-SecurityErst max-age=300; includeSubDomainspreload nur nach Prüfung aller Subdomains
X-Frame-OptionsDENY oder SAMEORIGINframe-ancestors ist moderner und genauer
Referrer-Policystrict-origin-when-cross-originKeine Tokens oder personenbezogenen Daten in URLs
Permissions-PolicyUngenutzte Funktionen abschaltenNur erlauben, was das Produkt wirklich braucht
X-Content-Type-OptionsnosniffMeist sinnvoll für die ganze Site

HSTS preload ist keine Standardoption für den ersten Tag. Die offizielle Preload-Seite empfiehlt eine schrittweise Erhöhung von max-age und warnt, dass ein Rückweg lange dauern kann. Eine alte Test-Subdomain ohne HTTPS reicht, um mit includeSubDomains; preload echten Schaden zu verursachen.

CSP als Rollout-Prozess

Der sichere Weg ist Beobachten, Einordnen, Erzwingen.

flowchart LR
  A["Ressourcen inventarisieren"] --> B["Report-Only CSP senden"]
  B --> C["Browser-Konsole und Reports sammeln"]
  C --> D["Ads, Analytics, CDN, iframes und Rauschen trennen"]
  D --> E["Nonce- oder Hash-basierte CSP aktivieren"]
  E --> F["Mit Security Headers und CSP Evaluator prüfen"]

Füge nicht jede gemeldete Domain automatisch hinzu. Browser-Erweiterungen, Unternehmens-Proxys, alte Tags und Angriffsversuche erzeugen ebenfalls Reports. Claude Code kann die Meldungen gruppieren, aber die Entscheidung bleibt fachlich: Gehört diese Ressource wirklich zum Produkt?

Next.js mit Nonce

Die aktuelle Next.js-App-Router-Dokumentation verwendet proxy.ts, um pro Request einen Nonce zu erzeugen. Ältere Projekte nutzen möglicherweise noch middleware.ts. Das Muster bleibt gleich: zufälligen Wert erzeugen, im Request-Header bereitstellen und denselben Wert in script-src setzen.

Ein Nonce pro Request hat Auswirkungen auf Rendering und Cache. Eine Seite, die immer einen neuen Nonce braucht, ist nicht einfach eine unveränderliche statische HTML-Datei. Für öffentliche Blogs oder Landingpages können CSP-Hashes oder ausgelagerte Skripte besser sein. Für Login, Checkout, Account und Admin ist ein Nonce oft sinnvoll.

// proxy.ts
import { NextRequest, NextResponse } from "next/server";

export function proxy(request: NextRequest) {
  const nonce = Buffer.from(crypto.randomUUID()).toString("base64");
  const isDev = process.env.NODE_ENV !== "production";

  const csp = [
    "default-src 'self'",
    `script-src 'self' 'nonce-${nonce}' 'strict-dynamic' ${isDev ? "'unsafe-eval'" : ""} https: http:`,
    `style-src 'self' ${isDev ? "'unsafe-inline'" : `'nonce-${nonce}'`} https://fonts.googleapis.com`,
    "font-src 'self' https://fonts.gstatic.com",
    "img-src 'self' data: blob: https:",
    "connect-src 'self' https://www.google-analytics.com https://analytics.google.com",
    "frame-src 'self' https://www.youtube-nocookie.com",
    "object-src 'none'",
    "base-uri 'self'",
    "form-action 'self'",
    "frame-ancestors 'none'",
    "upgrade-insecure-requests",
    "report-uri /api/csp-report",
  ].join("; ").replace(/\s{2,}/g, " ").trim();

  const requestHeaders = new Headers(request.headers);
  requestHeaders.set("x-nonce", nonce);

  const response = NextResponse.next({ request: { headers: requestHeaders } });
  response.headers.set("Content-Security-Policy", csp);
  response.headers.set("X-Content-Type-Options", "nosniff");
  response.headers.set("X-Frame-Options", "DENY");
  response.headers.set("Referrer-Policy", "strict-origin-when-cross-origin");
  response.headers.set("Permissions-Policy", "camera=(), microphone=(), geolocation=(), payment=(self)");
  response.headers.set("Strict-Transport-Security", "max-age=300; includeSubDomains");
  return response;
}

export const config = {
  matcher: ["/((?!api/csp-report|_next/static|_next/image|favicon.ico).*)"],
};

Bei Google Tag Manager muss der Nonce an das Snippet oder die Komponente weitergegeben werden. GTM startet über Inline-JavaScript, und Google empfiehlt dafür Nonces. Auch AdSense dokumentiert den Strict-CSP-Ansatz, weil Werbedomains sich ändern können. Eine statische Allowlist kann später Monetarisierung beschädigen.

CSP Reports sammeln

Report-Only ist nur nützlich, wenn Reports ankommen. Ein minimaler Next.js Route Handler sieht so aus:

// app/api/csp-report/route.ts
import { NextRequest, NextResponse } from "next/server";

export async function POST(request: NextRequest) {
  const contentType = request.headers.get("content-type") ?? "";
  const body = await request.text();

  const isReport =
    contentType.includes("application/csp-report") ||
    contentType.includes("application/reports+json") ||
    body.includes("violated-directive");

  if (!isReport) {
    return NextResponse.json({ ok: false }, { status: 415 });
  }

  console.warn("csp-report", body.slice(0, 4000));
  return new NextResponse(null, { status: 204 });
}

Speichere in Produktion keine vollständigen URLs, wenn Query-Parameter personenbezogene Daten enthalten können. Route, verletzte Directive, blocked URI, User Agent, Zeitstempel und Anzahl reichen oft. report-uri ist älter, bleibt aber aus Kompatibilitätsgründen praktisch. report-to kann ergänzen, sollte aber nicht die einzige Grundlage sein.

Astro, Express und Cloudflare

Astro kann feste Header gut in src/middleware.ts setzen. Für überwiegend statische Seiten ist es oft besser, Inline-Skripte zu reduzieren, statt Nonces zu erzwingen.

// src/middleware.ts
import { defineMiddleware } from "astro:middleware";

const securityHeaders: Record<string, string> = {
  "Content-Security-Policy-Report-Only": "default-src 'self'; script-src 'self' https://www.googletagmanager.com; img-src 'self' data: blob: https:; connect-src 'self' https://www.google-analytics.com; frame-src 'self' https://www.youtube-nocookie.com; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; report-uri /api/csp-report",
  "X-Content-Type-Options": "nosniff",
  "X-Frame-Options": "DENY",
  "Referrer-Policy": "strict-origin-when-cross-origin",
  "Permissions-Policy": "camera=(), microphone=(), geolocation=(), payment=(self)",
};

export const onRequest = defineMiddleware(async (_context, next) => {
  const response = await next();
  for (const [name, value] of Object.entries(securityHeaders)) {
    response.headers.set(name, value);
  }
  return response;
});

In Express ist Helmet der pragmatische Einstieg. Die CSP muss trotzdem zur Anwendung passen.

import crypto from "node:crypto";
import express from "express";
import helmet from "helmet";

const app = express();

app.use((req, res, next) => {
  res.locals.cspNonce = crypto.randomBytes(16).toString("base64");
  next();
});

app.use(helmet({
  contentSecurityPolicy: {
    useDefaults: false,
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'", (req, res) => `'nonce-${res.locals.cspNonce}'`, "'strict-dynamic'", "https:", "http:"],
      imgSrc: ["'self'", "data:", "blob:", "https:"],
      connectSrc: ["'self'", "https://www.google-analytics.com"],
      objectSrc: ["'none'"],
      baseUri: ["'self'"],
      frameAncestors: ["'none'"],
      reportUri: ["/csp-report"],
    },
  },
  strictTransportSecurity: { maxAge: 300, includeSubDomains: true },
  referrerPolicy: { policy: "strict-origin-when-cross-origin" },
  xFrameOptions: { action: "deny" },
}));

Cloudflare Pages nutzt _headers für statische Header. Diese Datei kann keine Request-Nonces erzeugen.

/*
  X-Content-Type-Options: nosniff
  X-Frame-Options: DENY
  Referrer-Policy: strict-origin-when-cross-origin
  Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(self)
  Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' https://www.googletagmanager.com; img-src 'self' data: blob: https:; connect-src 'self' https://www.google-analytics.com; frame-src 'self' https://www.youtube-nocookie.com; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; report-uri /csp-report

Anwendungsfälle und typische Fehler

Ein Content-Portal mit GA4, GTM, AdSense, externen Fonts, YouTube und Bild-CDN muss Sicherheit und Umsatz gleichzeitig betrachten. Report-Only zeigt, ob Anzeigen gerendert werden, Analytics-Events ankommen und Bilder laden. Eine perfekte Scan-Note hilft wenig, wenn die wichtigste Umsatzseite keine Anzeigen mehr ausliefert.

Ein SaaS-Adminbereich sollte deutlich restriktiver sein. Weniger Drittanbieter-Skripte, frame-ancestors 'none', object-src 'none', base-uri 'self' und ein enges form-action sind hier wichtiger. Payment-SDKs und Support-Widgets sollten nur auf Routen erlaubt sein, die sie wirklich brauchen.

Ein einbettbares Widget braucht eine eigene Policy. Wenn Kundenseiten es in iframes laden sollen, ist X-Frame-Options: DENY auf dieser Route falsch. Arbeite mit route-spezifischen Headern und klaren frame-ancestors.

Prüfung und Ergebnis

Prüfe mindestens Startseite, Login oder Formular sowie eine Embed- oder Checkout-Route.

curl -I https://example.com/
curl -I https://example.com/login
curl -I https://example.com/embed/widget

Danach helfen Security Headers für den Gesamtüberblick und CSP Evaluator für CSP-Schwächen. Die Note ist ein Signal, nicht das Ziel. Ziel ist eine passende Policy, die Schutz bietet und gleichzeitig Anzeigen, Analytics, Zahlungen und legitime iframes nicht beschädigt.

Im Test für diesen Artikel war Report-Only der wichtigste Schritt. GTM-Nonce-Probleme, GA4-connect-src, YouTube-frame-src und CDN-img-src wurden getrennt sichtbar. Claude Code konnte diese Reports klassifizieren und route-spezifische Verbesserungen vorschlagen, statt einfach Domains hinzuzufügen. Für eine Umsetzung in einem echten Repository sind Claude Code Training und Beratung oder ClaudeCodeLab Templates sinnvoll, damit die Regeln dauerhaft in CLAUDE.md landen.

#Claude Code #security #HTTP headers #CSP #web development
Kostenlos

Kostenloses PDF: Claude-Code-Cheatsheet

E-Mail eintragen und eine Seite mit Befehlen, Review-Gewohnheiten und sicheren Workflows herunterladen.

Wir schützen Ihre Daten und senden keinen Spam.

Masa

Über den Autor

Masa

Engineer für praktische Claude-Code-Workflows und Team-Einführung.