Sicherheit und Content-Security-Policy
Welche Einträge deine Content-Security-Policy für das Widget braucht, warum es ohne Inline-Skript und ohne unsafe-inline auskommt, wie es von deiner Seite isoliert ist und welche Geheimnisse nie in den Browser gehören.
Die Content-Security-Policy
Das Widget lädt keine fremden Schriften, kein Zählpixel und führt kein eval aus. Seine Stile setzt es über konstruierbare Stylesheets (adoptedStyleSheets) im Shadow DOM; sie fallen nicht unter style-src. Du brauchst deshalb kein unsafe-inline und kein unsafe-eval.
Mit den Adressen von reactive.chat:
Content-Security-Policy:
script-src 'self' https://cdn.reactive.chat;
connect-src 'self' wss://ws.reactive.chat https://ws.reactive.chat;
img-src 'self' data: https:;
Mit eigener Domain:
Content-Security-Policy:
script-src 'self' https://chat.deine-firma.de;
connect-src 'self' wss://chat.deine-firma.de https://chat.deine-firma.de;
img-src 'self' data: https:;
Die einzelnen Einträge:
- script-src – der Ort von
loader.js. Von dort kommen auch der Kern (core.<hash>.js) und die nachgeladenen Module (Touren, Datenschutztext, Shop). - connect-src mit wss:// – die Chat-Verbindung.
- connect-src mit https:// – dieselbe Adresse noch einmal: darüber laufen der HTTP-Rückfall, das Offline-Formular, Datei-Uploads, der Datenschutztext und Smart Answer. Fehlt dieser Eintrag, merkst du es nur in Netzen ohne WebSocket – dort kommt dann gar keine Verbindung zustande.
- img-src – Bilder im Chat: Logo und Avatare (deine
https://-Adressen oderdata:-Bilder), Bilder der Werbekarte und Vorschauen von Anhängen (von der Chat-Adresse). Wenn duimg-srcenger fassen willst, nimm mindestens die Chat-Adresse und die Hosts deiner Logo- und Kartenbilder auf. Ein gesperrtes Bild zeigt das Widget als Dateizeile statt als Vorschau.
Ältere Browser ohne konstruierbare Stylesheets (etwa Safari vor 16.4) fallen auf ein <style>-Element zurück, das eine strenge style-src blockiert. Das Widget funktioniert dort, ist aber ungestaltet.
Kein Inline-Skript nötig
Der Einbau besteht nur aus einem <script src> mit Attributen. Eigene Aufrufe (identify, track, open) gehören in deine eigenen Skriptdateien oder in ein Inline-Skript mit Nonce:
<script nonce="R4nd0mN0nc3">
ReactiveChat('identify', { userId: '4711', userHash: '…', exp: 1792503600 });
</script>
Eine Vorlage ohne Inline-Skript steht unter Besucher identifizieren.
Subresource Integrity
loader.js trägt keine Versionsnummer im Namen und wird laufend aktualisiert; ein integrity-Attribut würde den Chat beim nächsten Update stilllegen. Der Kern wird mit Inhalts-Hash im Namen nachgeladen (Architektur). Wenn deine Richtlinie SRI verlangt, liefere loader.js selbst aus und setze data-rc-ws-url (Schnellstart) – du übernimmst dann aber auch das Aktualisieren.
Isolation von deiner Seite
- Geschlossenes Shadow DOM. Deine Stile erreichen das Widget nicht, seine Stile erreichen deine Seite nicht – auch nicht bei globalen Resets.
- Keine Cookies. Das Widget setzt keine Cookies; Kennungen liegen im Speicher des Browsers, ohne Einwilligung nur im
sessionStorage(Datenschutz-Einbindung). - Kein Zugriff auf Formularfelder. Der Seitentext für den Assistenten liest nie Eingabefelder und läuft auf Seiten wie Konto, Checkout und Warenkorb gar nicht. Weitere Bereiche schließt du mit
data-rc-privateaus. - Persönliche Daten werden zweimal maskiert: im Browser, bevor eine Nachricht hinausgeht (Kartennummern mit Luhn-Prüfung, IBAN, E-Mail, Telefon, Steuer-Nummern), und auf dem Server vor dem Speichern. Sensible Query-Parameter (
email,password,token,key,card…) werden aus übertragenen Adressen entfernt. - Links und Bilder aus Nachrichten und Karten sind auf
https://beschränkt;javascript:unddata:-Links werden verworfen.
Herkunftsprüfung
Die Chat-Verbindung wird nur von den Domains angenommen, die im Projekt unter Erlaubte Herkünfte stehen (Subdomains eingeschlossen). Eine fremde Seite, die deinen Site-Key kopiert, bekommt origin_denied. Ist die Liste leer, findet keine Prüfung statt – trag deine Domains deshalb immer ein. Details unter Transport.
Der Site-Key selbst ist kein Geheimnis; er steht in jedem Seitenquelltext.
Was nie in den Browser gehört
- das Identitätsgeheimnis (für
userHash) – Identität - das Kundendaten-Endpunktgeheimnis
rckd_…– Kundendaten - das Webhook-Signaturgeheimnis – Webhooks
- API-Schlüssel
rc_live_…– Server-API - den Proxy-Schlüssel
rcpx_…– Eigene Domain
Auch nicht in eine App, ein öffentliches Repository oder die Adresse einer Seite.
Missbrauchsschutz
Der Server begrenzt Verbindungen, Rahmen und Nachrichten je Verbindung und je Adresse und sperrt bei wiederholten Verstößen (Close 1008). Hinter einem eigenen Proxy zählt er je Besucheradresse nur, wenn der Proxy-Schlüssel stimmt – sonst teilen sich alle Besucher die Adresse des Proxys. Zahlen unter Grenzen und Quoten.
Weiter: Eigene Domain
Ultima actualizare: