Zurück zum Blog
Implementierung20. August 20268 Min. LesezeitAktualisiert 30. August 2026

Content Security Policy für Website-Chatbots: Widget, API, Bilder und Streaming sicher freigeben

Eine praxistaugliche CSP für Website-Chatbots erlaubt nur die wirklich benötigten Skripte, API-Verbindungen, Streams und Bilder - ohne unnötige Wildcards.

Eine erwachsene Veranstaltungstechnikerin prüft auf einer sommerlichen Freiluftbühne ein gesichertes Anschlussmodul für ein Chatbot-Widget.

Ein Website-Chatbot besteht im Browser selten nur aus einer einzigen JavaScript-Datei. Ein Loader öffnet das Widget, eine API nimmt Nachrichten an, Antworten kommen als Stream zurück und Profilbilder oder Medien liegen möglicherweise auf einer weiteren Domain. Eine Content Security Policy (CSP) macht diese Wege sichtbar und begrenzt sie: Der Browser lädt oder verbindet nur, was die Website ausdrücklich erlaubt.

Das ist eine wichtige zweite Schutzschicht gegen Cross-Site Scripting und unerwartete Drittinhalte. Eine CSP repariert jedoch weder eine unsichere API noch fehlende Authentifizierung, mangelhafte Eingabevalidierung oder Prompt Injection. Sie reduziert die Möglichkeiten von eingeschleustem Code und begrenzt den Radius eines Fehlers. Entscheidend ist deshalb eine möglichst kleine, getestete Policy statt einer langen Liste pauschal freigegebener Domains.

Warum Chatbot-Widgets besondere CSP-Regeln brauchen

Bei einer klassischen Inhaltsseite reichen oft Ressourcen vom eigenen Ursprung. Ein Chatbot kommuniziert dagegen nach dem Laden weiter. connect-src steuert unter anderem fetch(), XMLHttpRequest, EventSource, WebSocket und sendBeacon(). Genau hier laufen Nachrichten, Streaming-Antworten, Feedback-Ereignisse und gegebenenfalls Telemetrie. Fehlt der richtige Ursprung, erscheint das Widget zwar, kann aber nicht antworten.

Andere Bestandteile fallen unter eigene Direktiven. script-src entscheidet über den Widget-Loader, img-src über Avatare und Antwortbilder, style-src über Stylesheets und font-src über externe Schriften. Ein iframe-basiertes Widget benötigt zusätzlich frame-src. default-src dient als Rückfall für viele nicht ausdrücklich genannte Ressourcentypen, ersetzt aber keine bewusste Bestandsaufnahme.

Die wichtigste Vorarbeit findet deshalb nicht im CSP-Generator statt, sondern im Browser: Öffnen Sie eine repräsentative Seite, starten Sie eine Unterhaltung, lassen Sie eine lange Antwort streamen, öffnen Sie Quellen, senden Sie Feedback und testen Sie Fehler- sowie Handoff-Fälle. Im Netzwerk-Panel sehen Sie die tatsächlich angesprochenen Origins. Dokumentieren Sie zu jedem Host den Zweck, den Ressourcentyp und eine verantwortliche Person.

Die vier relevanten Datenwege getrennt freigeben

1. Widget-Skript und Initialisierung

Beziehen Sie den Loader möglichst von einer stabilen, versionierten Adresse. Eine Freigabe wie script-src https: wäre zu breit, weil damit Skripte von jeder HTTPS-Domain zulässig würden. Erlauben Sie stattdessen den exakten CDN-Origin oder liefern Sie den Loader selbst aus. Wenn die Integration Inline-Code benötigt, verwenden Sie einen pro HTTP-Antwort neu erzeugten Nonce oder einen passenden Hash. 'unsafe-inline' sollte nicht zur schnellen Dauerlösung werden.

Ein Nonce gehört nur an Skripte, die das serverseitige Template selbst erzeugt. Eine Middleware, die blind jedem vorhandenen Script-Tag denselben Nonce ergänzt, würde auch eingeschleusten Tags Vertrauen geben. Für ein statisches, versioniertes Fremdskript kann Subresource Integrity zusätzlich helfen; bei häufig wechselnden Dateien muss der Hash allerdings kontrolliert aktualisiert werden.

2. API, Server-Sent Events und WebSocket

Normale POST-Anfragen und eine über fetch() gestreamte Antwort benötigen den HTTPS-API-Origin in connect-src. Server-Sent Events über EventSource fallen ebenfalls darunter. Für einen WebSocket tragen Sie den konkreten wss://-Origin ausdrücklich ein. MDN weist darauf hin, dass 'self' WebSocket-Schemata nicht in allen Browsern automatisch umfasst. Eine eigene Direktive namens stream-src gibt es nicht.

CSP und CORS lösen unterschiedliche Aufgaben. CSP bestimmt, wohin die Seite überhaupt verbinden darf; CORS bestimmt serverseitig, welche Ursprünge eine Antwort im Browser lesen dürfen. Eine CSP-Freigabe behebt deshalb weder einen CORS-Fehler noch ein abgelaufenes Zugriffstoken. Ein Same-Origin-Proxy kann die Policy vereinfachen, muss aber Authentifizierung, Rate Limits, Zeitüberschreitungen und Fehlerweitergabe weiterhin korrekt behandeln.

3. Bilder, Avatare und erzeugte Medien

Erlauben Sie in img-src nur den eigenen Ursprung und den tatsächlich verwendeten Medien-Origin. data: ist nur nötig, wenn das Widget kleine eingebettete Bilder verwendet; blob: nur, wenn der Browser Bilder tatsächlich als Blob-URL erzeugt. Jede zusätzliche Quelle vergrößert die Angriffsfläche. Wird ein Bild zuerst per fetch() geladen und danach in eine Blob-URL umgewandelt, können sowohl connect-src als auch img-src betroffen sein.

Testen Sie nicht nur den Standardavatar. Prüfen Sie Vorschaubilder, Quellen-Screenshots, Dateianhänge, Dark Mode und die Fehlerdarstellung für nicht verfügbare Medien. URL-Parameter können vertrauliche Informationen in CSP-Berichte tragen; Reporting-Endpunkte sollten Berichte deshalb datensparsam verarbeiten und nicht unbegrenzt aufbewahren.

4. iframe, Styles, Fonts und optionale Worker

Ein direkt in den DOM eingebettetes Widget braucht meist keinen fremden Frame. Dann kann frame-src 'none' bleiben. Läuft der Chat dagegen in einem iframe, erlauben Sie ausschließlich dessen exakten Origin. Davon zu unterscheiden ist frame-ancestors: Diese Direktive legt auf der ausgelieferten Ressource fest, welche Seiten sie einbetten dürfen. Der Widget-Anbieter muss sie daher auf seiner iframe-Antwort passend setzen.

Bei Styles und Fonts gilt dasselbe Prinzip. Erlauben Sie konkrete Hosts und vermeiden Sie 'unsafe-inline', soweit die Integration das zulässt. Worker oder Audiofunktionen kommen nur hinzu, wenn das Produkt sie wirklich verwendet. Eine vorsorgliche Freigabe von blob:, ganzen Wildcard-Domains oder beliebigen Medienquellen erschwert spätere Audits.

Ein realistisches CSP-Beispiel für ein Chatbot-Widget

Die folgenden Domains sind bewusst reservierte Beispieldomains. Ersetzen Sie sie durch die Origins aus Ihrer eigenen Netzwerk-Analyse. Das Beispiel nimmt einen externen Loader, eine HTTPS-API, einen getrennten WebSocket für Streaming und einen Medienhost an. Es verwendet keine pauschalen Wildcards:

Content-Security-Policy:
  default-src 'self';
  script-src 'self' https://cdn.chat.example 'nonce-{RANDOM}';
  connect-src 'self' https://api.chat.example wss://stream.chat.example;
  img-src 'self' data: https://media.chat.example;
  style-src 'self' 'nonce-{RANDOM}';
  font-src 'self';
  frame-src 'none';
  worker-src 'self';
  object-src 'none';
  base-uri 'self';
  frame-ancestors 'self';
  form-action 'self';
  upgrade-insecure-requests;

{RANDOM} steht für einen starken, pro Antwort neu erzeugten Wert, der im Header und an den erlaubten Script- beziehungsweise Style-Elementen identisch ist. Nutzt Ihr Widget ein iframe, ersetzen Sie frame-src 'none' durch den genauen Widget-Origin. Nutzt es ausschließlich HTTPS-Streaming über fetch() oder EventSource, entfällt der WebSocket-Origin. Entfernen Sie jede Quelle, die nach einem vollständigen Funktionstest nicht benötigt wird.

Die Policy ist ein praxistauglicher Ausgangspunkt, keine universelle Vorlage. Eine moderne strikte CSP kann Skripte noch stärker über Nonces oder Hashes und 'strict-dynamic' steuern. Ob das ohne Kompatibilitätsprobleme möglich ist, hängt davon ab, wie der Loader weitere Skripte erzeugt. Klären Sie diesen Ablauf mit dem Anbieter und testen Sie Browser, Consent-Modus und Deployment-Varianten.

Von Report-Only zur erzwungenen Policy

Schalten Sie eine neue Policy nicht ungeprüft scharf. Der W3C-Mechanismus Content-Security-Policy-Report-Only meldet Verstöße, ohne Ressourcen zu blockieren. So erkennen Sie vergessene Bildhosts, einen abweichenden Streaming-Origin oder Inline-Code, bevor Nutzer davon betroffen sind. OWASP empfiehlt den HTTP-Header als bevorzugten Auslieferungsweg; er unterstützt im Gegensatz zum Meta-Element auch den vollständigen Funktionsumfang.

  1. Inventar erstellen: Testen Sie Widget-Start, erste Nachricht, lange Streaming-Antwort, Quellen, Bilder, Feedback, Handoff und Consent-Wechsel auf mehreren Seitentypen.
  2. Report-Only ausrollen: Beginnen Sie mit der geplanten engen Policy und sammeln Sie Verstöße in einem begrenzten Zeitraum. Filtern Sie Browser-Erweiterungen und andere nicht reproduzierbare Störsignale.
  3. Jeden Host begründen: Erweitern Sie die Policy nur, wenn eine konkrete Produktfunktion den Ursprung benötigt. Vermeiden Sie Wildcards als Reaktion auf einzelne Meldungen.
  4. Automatisiert testen: Ergänzen Sie End-to-End-Tests, die eine Nachricht senden, Streaming abwarten und ein Bild laden. Prüfen Sie gleichzeitig die Browser-Konsole auf CSP-Verstöße.
  5. Erzwingen und beobachten: Aktivieren Sie den Content-Security-Policy-Header, behalten Sie parallel eine noch strengere Report-Only-Variante im Blick und vergleichen Sie Fehlerraten.

Ein gestufter Rollout passt gut zu einem Chatbot im Shadow Mode. Für Streaming-spezifische Messwerte hilft der Beitrag zu Latenzbudgets und Timeouts. CSP-Verstöße sollten dabei als eigenes Signal gelten: Ein Timeout und eine blockierte Verbindung brauchen unterschiedliche Ursachenanalyse.

Typische Fehlkonfigurationen

  • Zu breite Quelllisten: *, https: oder große Wildcard-Domains machen die Policy bequem, aber schwach und schwer überprüfbar.
  • Nur der sichtbare Start wird getestet: Das Widget öffnet sich, doch Streaming, Feedback, Bilder oder Handoff scheitern erst später.
  • 'unsafe-inline' bleibt dauerhaft: Eine kurzfristige Kompatibilitätshilfe wird nicht durch Nonces, Hashes oder externen Code ersetzt.
  • CSP wird mit Zugriffskontrolle verwechselt: Die Policy ersetzt keine serverseitigen Rechte, keine Session-Prüfung und keinen Schutz vor missbräuchlichen Tool-Aufrufen.
  • Berichte enthalten zu viele Daten: Vollständige URLs, Query-Parameter oder Nutzerkontext landen unnötig lange im Monitoring.
  • Staging und Produktion driften: Unterschiedliche CDN-, API- oder WebSocket-Hosts werden erst nach dem Go-live sichtbar.

Auch ein enger script-src macht einen erlaubten Drittanbieter nicht automatisch sicher: Sein JavaScript läuft mit den Möglichkeiten, die Ihre Seite ihm gibt. Prüfen Sie deshalb Anbieterwechsel, neue Subdomains und Loader-Updates wie andere sicherheitsrelevante Abhängigkeiten. Der Beitrag zu Prompt-Injection-Schutz ergänzt diese Browsergrenze um Regeln für RAG, Tools und Daten.

Checkliste vor dem Go-live

  • Sind alle benötigten Origins aus echten Browser-Sitzungen dokumentiert und fachlich begründet?
  • Erlaubt script-src nur den Loader und kontrollierte Skripte, ohne pauschales 'unsafe-inline'?
  • Enthält connect-src die exakten HTTPS-, EventSource- und gegebenenfalls WSS-Origins?
  • Sind Bild-, Style-, Font-, Frame- und Worker-Quellen getrennt und so eng wie möglich definiert?
  • Werden Nonces pro Antwort neu erzeugt und nur an vertrauenswürdige Elemente gesetzt?
  • Wurden Consent-Wechsel, lange Streams, Bilder, Fehler, Handoff sowie Desktop und Mobilgeräte getestet?
  • Ist die Policy zunächst in Report-Only beobachtet und danach als Header erzwungen worden?
  • Werden CSP-Berichte ohne unnötige personenbezogene oder vertrauliche URL-Daten verarbeitet?
  • Gibt es nach Widget- oder Infrastruktur-Updates einen automatisierten Regressionstest?

Fazit

Eine gute CSP für Website-Chatbots ist keine Sammlung von Ausnahmen, sondern eine technische Landkarte der erlaubten Browserwege. Trennen Sie Loader, API, Streaming, Bilder und iframe-Ressourcen, erlauben Sie exakte Origins und führen Sie die Policy zuerst im Report-Only-Modus ein. So bleibt das Widget funktionsfähig, während unerwartete Skripte und Verbindungen deutlich weniger Spielraum erhalten.

Quellen

Verwandeln Sie Website-Besuche in bessere Gespräche

Starten Sie einen KI-Chatbot, der von Tag eins nützlich ist

Trainieren Sie ChatReact mit Ihrer Website, Dokumenten und geprüften Fakten, damit Besucher schneller Antworten erhalten und Ihr Team weniger repetitive Anfragen bekommt.

Verwandte Artikel

Weiterlesen