Für InfoSec-Teams und App-Reviews
Sicherheit bei Peel
Die Kurzfassung: Board-Inhalte werden im Browser mit einem Schlüssel verschlüsselt, der im Fragment des Links steckt. Unsere Server speichern und verteilen also Chiffretext, den sie nicht lesen können. Hier steht genau, wie das funktioniert und wo die Grenzen liegen.
Zusammenfassung
- Kartentexte, Namen, Board-Titel, Stimmen und Sticker werden mit AES-256-GCM unter einem im Browser erzeugten Board-Schlüssel verschlüsselt. Der Schlüssel reist im URL-Fragment (
#k=) mit und wird nie an einen Server gesendet. - Moderationsaktionen, der Board-Header und Snapshots werden mit dem Ed25519-Schlüssel der Moderation signiert. Die Board-ID wird aus diesem Schlüssel abgeleitet, sodass Clients einen Schlüsseltausch erkennen.
- Verdeckte Karten sind bis zum Aufdecken für die Moderation versiegelt (X25519 Sealed Box) und über gesalzene Commitments gebunden, damit aufgedeckter Text nicht ausgetauscht werden kann.
- Standardmäßig anonym: Operationen enthalten keine Autor-ID; Stimmen und Reaktionen nutzen eine zufällige ID pro Board.
- Teilnehmende authentifizieren sich nie. Keine Analytics-SDKs, keine Werbung, keine Drittanbieter-Skripte außer Paddle.js auf der Checkout-Seite.
- Ausschließlich Cloudflare. Nicht beanspruchte Boards werden 60 Tage nach dem letzten Besuch gelöscht.
Wie Daten fließen
Das Fragment einer URL (alles nach dem #) verarbeitet der Browser selbst; es ist nicht Teil der HTTP-Anfrage. Genau dort legt Peel den Board-Schlüssel ab.
Bedrohungsmodell
Wir bauen so, dass ein vollständig kompromittierter oder neugieriger Server – wir eingeschlossen – so wenig wie möglich darüber erfährt, was ein Team sagt.
Was wir schützen
- Kartentexte, GIF-Auswahl und im Modus mit Namen den Namen der Person, die geschrieben hat.
- Namen und Avatare der Teilnehmenden, den Board-Namen und eigene Vorlagentitel.
- Wer worüber abgestimmt oder worauf reagiert hat und wer welche Karte geschrieben hat.
- Die Integrität der Retro: Schritte, Aufdecken und Entscheidungen der Moderation lassen sich nicht fälschen.
Angreifer, die wir berücksichtigen
- Unsere eigenen Server, böswillige Insider oder jemand, der in unseren Speicher eindringt: Sie bekommen Chiffretext und Metadaten.
- Angreifer im Netzwerk: TLS überall; der Schlüssel geht nie übers Netz.
- Ein Server, der Schlüssel austauscht: Die Board-ID wird aus dem öffentlichen Schlüssel der Moderation abgeleitet, und Clients prüfen den signierten Header.
- Teilnehmende, die spicken oder fälschen wollen: Verdeckte Karten sind für die Moderation versiegelt; Moderationsoperationen brauchen die Signatur der Moderation; Kartenänderungen brauchen den Schlüssel der Karte.
- Die Moderation, die für eine offline gegangene Person neu veröffentlicht: Commitments verhindern, dass der Text verändert wird.
Ehrlich gesagt: nicht abgedeckt
- Wer den Teilnahmelink hat, kann das Board lesen. Der Link ist die Zugangskontrolle. Teile ihn so sorgfältig wie das Board selbst.
- Ein kompromittiertes Gerät, eine bösartige Browser-Erweiterung oder jemand, der dir über die Schulter schaut.
- Traffic-Analyse: Der Server sieht Zeitpunkte, Größen und Anzahlen (siehe Datenübersicht).
- Denial of Service durch den Server: Er kann Nachrichten verwerfen oder verzögern, aber nicht lesen oder fälschen.
Kryptografie
Alle Primitive stammen aus der WebCrypto-API des Browsers. Keine selbstgebaute Kryptografie, keine Krypto-Bibliotheken von Drittanbietern.
| Schlüssel | Algorithmus | Verwendet für |
|---|---|---|
| K_board | AES-256-GCM, 96-Bit-Zufalls-IV | Verschlüsselt jede Operation, jeden Snapshot und jedes Presence-Update. Die Additional Data binden Board-ID, Operationstyp und Operations-ID, sodass Chiffretext nicht in ein anderes Board oder einen anderen Slot eingespielt werden kann. Existiert nur im Link-Fragment #k=. |
| K_owner | Ed25519 | Die Befugnis der Moderation. Signiert Moderationsoperationen (Schritt, Timer, Spotlight, Vorlage, Einstellungen, Öffnen der Stimmen, Ausblenden einer Karte), den Board-Header und Snapshots. Ein streng monoton steigender Zähler verhindert Replays. Nur im Moderationslink (&o=). |
| Board-ID | SHA-256, erste 80 Bit, Base32 | Aus dem öffentlichen Schlüssel der Moderation abgeleitet – die ID selbst beweist also, welchem Schlüssel das Board gehört. Clients lehnen einen Header ab, dessen Schlüssel nicht auf die ID hasht. |
| K_fac | X25519 Sealed Box: ephemeres X25519 + HKDF-SHA256 + AES-256-GCM | Verdeckte Karten werden beim Schreiben für den öffentlichen Schlüssel der Moderation versiegelt. Nur der Moderationslink (&f=) kann sie öffnen. |
| Kartenschlüssel | Ed25519, ein Schlüssel pro Karte | Liegt nur bei der Person, die die Karte geschrieben hat. Änderungen und das Aufdecken werden damit signiert: Authentizität ohne Identität. |
| Commitments | HMAC-SHA256 mit 128-Bit-Zufallssalt | Eine verdeckte Karte veröffentlicht ein Commitment auf ihren Inhalt. Beim Aufdecken werden Inhalt und Salt veröffentlicht und von jedem Client geprüft – so kann niemand den Text austauschen. |
| Presence | AES-256-GCM unter K_board | Namen, Avatare und Tipp-Anzeigen sind verschlüsselt wie alles andere. |
| Schlüsselbündel | HKDF-SHA256 aus Passkey-PRF oder Wiederherstellungscode, AES-256-GCM | Angemeldete Moderator:innen können Board-Schlüssel geräteübergreifend synchronisieren. Das Bündel wird auf dem Gerät verschlüsselt; der Server speichert nur Chiffretext und gewrappte Schlüssel. |
Signierte Nachrichten sind domänengetrennt (zum Beispiel peel/sig/v1, peel/header/v1, peel/snap/v1), damit eine Signatur für einen Zweck nicht für einen anderen wiederverwendet werden kann.
Anonymität
- Operationen enthalten keine Autor-ID. Der Server kann eine Karte keiner Person zuordnen – und standardmäßig kann es die Moderation auch nicht.
- Stimmen und Reaktionen sind an eine zufällige ID pro Board gebunden, die mit keinem Namen verknüpft ist.
- Tipp-Anzeigen zeigen, dass jemand schreibt – nie, was.
- Der Modus mit Namen ist eine explizite Board-Einstellung; der Name reist dann innerhalb der verschlüsselten Karte.
- Teilnehmende melden sich nie an, es gibt also kein Konto, das sich verknüpfen ließe.
Datenübersicht
Alles, was wir speichern, wo es liegt, wer es lesen kann und wie lange es bleibt.
| Daten | Wo | Lesbar für | Aufbewahrung |
|---|---|---|---|
| Karten, Stimmen, Reaktionen, Sticker, Maßnahmen, Board-Name, eigene Vorlagentitel | Durable-Object-Speicher, als Chiffretext | Alle mit dem Board-Link | Bis das Board gelöscht wird |
| Operations-Umschlag: Typ, Server-Sequenz und -Zeit, Größe, Moderationszähler | Durable-Object-Speicher | Peel | Bis das Board gelöscht wird |
| Namen und Avatare der Teilnehmenden, Tipp-Status | Als Chiffretext weitergeleitet; während der Verbindung im Arbeitsspeicher | Alle mit dem Board-Link | Während der Verbindung |
| Board-Status: Schritt, Anzahl Teilnehmende und Karten, Katalog-Vorlagen-ID, Sperr-Flag, Erstellungs- und Ablaufzeit | Durable Object, D1; Slack-/Teams-Nachrichten, falls installiert | Peel; euer Slack-/Teams-Channel | Lebensdauer des Boards |
| Moderationskonto: Anbieter-ID, Name, E-Mail (falls freigegeben), verknüpfte Anbieter, Erstellungsdatum, Sitzung | D1 | Peel | Bis du das Konto löschst |
| Schlüsselbündel und gewrappte Schlüssel | D1, als Chiffretext | Nur du (Passkey oder Wiederherstellungscode) | Bis du das Konto löschst |
| Tarif, Abo-Status, Paddle-Kunden- und -Abo-IDs | D1; Paddle | Peel, Paddle | Wie steuerrechtlich vorgeschrieben |
| Slack-/Teams-Workspace-, Channel- und Nachrichten-IDs; Bot-Token (AES-GCM-verschlüsselt) | D1 | Peel | Bis zur Deinstallation |
| IP-Adresse | Cloudflare-Edge, flüchtig (Auslieferung, Rate-Limits) | Cloudflare, Peels Rate-Limiter | Nicht in unseren Datenbanken gespeichert |
| Tägliche Zähler (erstellte Boards, erreichte Schritte) | D1 | Peel | Nur aggregiert, ohne Kennungen |
Was unser Server kann und was nicht
Er kann
- Operationstypen, Größen, Zeitpunkte, den Schritt, Anzahl Teilnehmende und Karten, die Katalog-Vorlagen-ID und das Sperr-Flag sehen.
- Operationen verwerfen, verzögern oder nicht zustellen (Denial of Service).
- IP-Adressen am Netzwerkrand sehen.
- Boards und erreichte Schritte zählen, aggregiert.
- Ein Board löschen (Ablauf, Missbrauchsmeldungen).
Er kann nicht
- Kartentexte, Namen, Board-Titel, eigene Vorlagentitel, Stimmen oder Sticker lesen.
- Verdeckte Karten vor dem Aufdecken lesen (und auch danach nicht).
- Moderationsaktionen fälschen: Dafür braucht es die Signatur der Moderation.
- Eigene Schlüssel unterschieben: Die Board-ID würde ihn verraten.
- Den aufgedeckten Text einer Karte ändern: Commitments und Kartensignaturen würden ihn verraten.
- Erkennen, wer welche Karte geschrieben hat.
Wie bei jeder Web-App vertraust du dem Code, den wir ausliefern. Diese Angriffsfläche halten wir klein: eine strikte Content Security Policy, script-src beschränkt auf unsere eigene Origin, keine Drittanbieter-Skripte, und das Protokoll legen wir auf Anfrage zur Prüfung offen.
Slack und Microsoft Teams
- Nachrichten enthalten den Board-Link und Metadaten (Titel, Schritt, Anzahlen). Kartentext wird nur gesendet, wenn die Moderation eine Zusammenfassung postet und bestätigt.
- Die Beitrittskarte enthält den Teilnahmelink inklusive Schlüssel. Wer den Channel lesen kann, kann beitreten – genau wie bei einem dort eingefügten Link.
- Link-Vorschauen zeigen nur Schritt und Anzahlen, nie Inhalte.
- Slack-Scopes:
commands,chat:write,links:read,links:write;users:readnur, wenn ein Team Erwähnungen aktiviert. - Bot-Tokens sind im Ruhezustand verschlüsselt (AES-GCM, Schlüssel als Worker-Secret). Slack-Request-Signaturen und Bot-Framework-Tokens werden bei jeder Anfrage geprüft.
- Wird die App deinstalliert, endet jedes Posten und ihre Tokens werden gelöscht.
Web und Infrastruktur
- Ausschließlich Cloudflare: Pages, Workers, Durable Objects, D1, R2 und KV im Konto von 1801 Labs. Keine anderen Server.
- TLS überall, HSTS und eine strikte Content Security Policy.
- Keine Analytics-SDKs, keine Werbung, keine Drittanbieter-Skripte. Einzige Ausnahme ist Paddle.js, das nur auf der Checkout-Seite geladen wird.
- Ein Cookie, nur für angemeldete Moderator:innen:
peel_session, httpOnly, Secure, SameSite=Lax. - GIF-Suche und Medien laufen über unsere API, die IP-Adressen der Teilnehmenden erreichen GIPHY also nie.
- Schriften und Assets liegen bei uns selbst. Keine CDN-Fonts, keine Tracking-Pixel.
- Rate-Limits pro IP und pro Board; Missbrauchsmeldungen und eine Sperre durch die Moderation.
Konten und Aufbewahrung
- Teilnehmende authentifizieren sich nie. Moderator:innen melden sich mit Google (oder Entra ID über Teams) an – nur, um Boards zu behalten oder bezahlte Funktionen zu nutzen.
- Ein Konto speichert eine ID, Name und E-Mail vom Anbieter sowie ein verschlüsseltes Schlüsselbündel, das per Passkey (WebAuthn PRF) oder Wiederherstellungscode entsperrt wird. Die Anmeldung verleiht Besitz, keinen Zugriff auf Inhalte.
- Beim Beanspruchen eines Boards wird der Besitz mit einer Moderationssignatur nachgewiesen. Board-Schlüssel werden nie gesendet.
- Boards ohne Konto werden 60 Tage nach dem letzten Besuch gelöscht; jeder Besuch setzt die Frist zurück. Durable-Object-Alarme löschen den Speicher.
- Wenn du dein Konto löschst, werden Sitzungen, Schlüsselbündel und deine Bibliothek gelöscht, und deine Boards bekommen wieder die 60-Tage-Frist.
Responsible Disclosure
Etwas gefunden? Sag es uns zuerst, dann arbeiten wir gemeinsam daran. Wir bestätigen Meldungen innerhalb von drei Werktagen.
- Bitte gib uns angemessen Zeit (wir peilen 90 Tage an), das Problem zu beheben, bevor du es veröffentlichst.
- Teste mit deinen eigenen Boards und Konten. Greif nicht auf Daten anderer zu und beeinträchtige den Dienst nicht.
- Gegen Forschung in gutem Glauben, die sich an diese Regeln hält, gehen wir nicht rechtlich vor.
- Maschinenlesbarer Kontakt:
/.well-known/security.txt.
Kund:innen im Unternehmens-Tarif erhalten ein Security-Review-Paket (Antworten auf Fragebögen, Unterauftragsverarbeiter, Datenflüsse). AVV · Datenschutz