Til InfoSec-teams og app-reviewere
Sikkerhed i Peel
Kort fortalt: tavlens indhold krypteres i browseren med en nøgle, der ligger i linkets fragment, så vores servere gemmer og videresender krypteret tekst, de ikke kan læse. Her er præcis hvordan, og hvor grænserne går.
Opsummering
- Tekst fra kort, navne, tavletitler, stemmer og stickers krypteres med AES-256-GCM under en tavlenøgle, der genereres i browseren. Nøglen rejser i URL-fragmentet (
#k=) og sendes aldrig til en server. - Facilitatorhandlinger, tavlens header og snapshots signeres med facilitatorens Ed25519-nøgle. Tavle-id’et udledes af den nøgle, så klienterne opdager, hvis nøglen bliver skiftet ud.
- Skjulte kort er forseglet til facilitatoren (X25519 sealed box) indtil afsløringen og bundet af saltede commitments, så den afslørede tekst ikke kan byttes ud.
- Anonymt som standard: operationer indeholder intet forfatter-id; stemmer og reaktioner bruger et tilfældigt id pr. tavle.
- Deltagere autentificerer sig aldrig. Ingen analyse-SDK’er, ingen reklamer, ingen tredjepartsscripts bortset fra Paddle.js på betalingssiden.
- Kun Cloudflare. Tavler uden ejer slettes 60 dage efter sidste besøg.
Sådan flyder data
Fragmentet i en URL (alt efter #) håndteres af browseren og er ikke en del af HTTP-forespørgslen. Det er der, Peel lægger tavlens nøgle.
Trusselsmodel
Vi designer sådan, at en fuldt kompromitteret eller nysgerrig server, inklusive os selv, lærer så lidt som muligt om, hvad et team siger.
Det beskytter vi
- Tekst fra kort, valg af GIF’er og, i tilstanden med navn, forfatterens navn.
- Deltagernes navne og avatarer, tavlens navn og titler på egne skabeloner.
- Hvem der stemte på eller reagerede på hvad, og hvem der skrev hvilket kort.
- Retroens integritet: trin, afsløringer og facilitatorens beslutninger kan ikke forfalskes.
Modstandere, vi tager højde for
- Vores egne servere, en ondsindet insider eller nogen, der bryder ind i vores lager: de får krypteret tekst og metadata.
- En angriber på netværket: TLS overalt; nøglen krydser aldrig netværket.
- En server, der bytter nøgler ud: tavle-id’et udledes af facilitatorens offentlige nøgle, og klienterne verificerer den signerede header.
- En deltager, der vil kigge eller forfalske: skjulte kort er forseglet til facilitatoren; facilitatoroperationer kræver facilitatorens signatur; redigering af kort kræver kortets nøgle.
- En facilitator, der genudgiver for en forfatter, der er offline: commitments forhindrer, at teksten ændres.
Uden for rammerne, helt ærligt
- Alle, der har deltagerlinket, kan læse tavlen. Linket er adgangskontrollen. Del det, som du ville dele selve tavlen.
- En kompromitteret enhed, en ondsindet browserudvidelse eller nogen, der kigger dig over skulderen.
- Trafikanalyse: serveren ser tidspunkter, størrelser og antal (se datakortet).
- Tjenestenægtelse fra serveren: den kan droppe eller forsinke beskeder, men ikke læse eller forfalske dem.
Kryptografi
Alle primitiver kommer fra browserens WebCrypto API. Ingen hjemmelavet kryptografi, ingen kryptobiblioteker fra tredjepart.
| Nøgle | Algoritme | Bruges til |
|---|---|---|
| K_board | AES-256-GCM, tilfældig 96-bit IV | Krypterer hver operation, hvert snapshot og hver tilstedeværelsesopdatering. De ekstra data binder tavle-id, operationstype og operations-id, så krypteret tekst ikke kan genafspilles i en anden tavle eller plads. Findes kun i linkets fragment #k=. |
| K_owner | Ed25519 | Facilitatorens autoritet. Signerer facilitatoroperationer (trin, nedtælling, fokus, skabelon, indstillinger, åbning af stemmer, skjulning af et kort), tavlens header og snapshots. En strengt stigende tæller forhindrer genafspilning. Findes kun i facilitatorlinket (&o=). |
| Tavle-id | SHA-256, de første 80 bit, base32 | Udledes af facilitatorens offentlige nøgle, så id’et i sig selv beviser, hvilken nøgle der ejer tavlen. Klienterne afviser en header, hvis nøgle ikke hasher til id’et. |
| K_fac | X25519 sealed box: flygtig X25519 + HKDF-SHA256 + AES-256-GCM | Skjulte kort forsegles til facilitatorens offentlige nøgle, mens folk skriver. Kun facilitatorlinket (&f=) kan åbne dem. |
| Kortnøgler | Ed25519, én nøgle pr. kort | Kun forfatteren har den. Redigeringer og afsløringen signeres med den: ægthed uden identitet. |
| Commitments | HMAC-SHA256 med et tilfældigt 128-bit salt | Et skjult kort offentliggør et commitment til sit indhold. Ved afsløringen offentliggøres indhold og salt, og alle klienter tjekker dem, så ingen kan bytte teksten ud. |
| Tilstedeværelse | AES-256-GCM under K_board | Navne, avatarer og skriveindikatorer krypteres ligesom alt andet. |
| Nøglebundt | HKDF-SHA256 fra adgangsnøglens PRF eller gendannelseskode, AES-256-GCM | Facilitatorer, der er logget ind, kan synkronisere tavlenøgler på tværs af enheder. Bundtet krypteres på enheden; serveren gemmer kun krypteret tekst og indpakkede nøgler. |
Signeringsbeskeder er domæneadskilte (f.eks. peel/sig/v1, peel/header/v1, peel/snap/v1), så en signatur til ét formål ikke kan genbruges til et andet.
Anonymitet
- Operationer indeholder intet forfatter-id. Serveren kan ikke koble et kort til en person, og som standard kan facilitatoren heller ikke.
- Stemmer og reaktioner er knyttet til et tilfældigt id pr. tavle, der ikke er koblet til et navn.
- Skriveindikatorer viser, at nogen skriver, aldrig hvad.
- Tilstanden med navn er en udtrykkelig tavleindstilling; forfatterens navn rejser så inde i det krypterede kort.
- Deltagere logger aldrig ind, så der er ingen konto at koble sammen.
Datakort
Alt, hvad vi har, hvor det ligger, hvem der kan læse det, og hvor længe det bliver.
| Data | Hvor | Kan læses af | Gemmes |
|---|---|---|---|
| Kort, stemmer, reaktioner, stickers, handlinger, tavlens navn, titler på egne skabeloner | Durable Object-lager, som krypteret tekst | Personer med tavlens link | Indtil tavlen slettes |
| Operationens kuvert: type, serverens sekvensnummer og tidspunkt, størrelse, facilitatortæller | Durable Object-lager | Peel | Indtil tavlen slettes |
| Deltagernes navne, avatarer, skriveaktivitet | Videresendes som krypteret tekst; holdes i hukommelsen, mens man er forbundet | Personer med tavlens link | Mens man er forbundet |
| Tavlestatus: trin, antal deltagere og kort, katalogets skabelon-id, låseflag, oprettelses- og udløbstidspunkt | Durable Object, D1; Slack-/Teams-beskeder, hvis installeret | Peel; jeres Slack-/Teams-kanal | Tavlens levetid |
| Facilitatorkonto: udbyder-id, navn, e-mail hvis delt, tilknyttede udbydere, oprettelsesdato, session | D1 | Peel | Indtil du sletter kontoen |
| Nøglebundt og indpakkede nøgler | D1, som krypteret tekst | Kun dig (adgangsnøgle eller gendannelseskode) | Indtil du sletter kontoen |
| Abonnement, abonnementsstatus, Paddle-kunde- og abonnements-id’er | D1; Paddle | Peel, Paddle | Så længe skattelovgivningen kræver |
| Slack-/Teams-workspace, kanal- og besked-id’er; bot-token (AES-GCM-krypteret) | D1 | Peel | Indtil appen afinstalleres |
| IP-adresse | Cloudflares edge, midlertidigt (levering, hastighedsbegrænsning) | Cloudflare, Peels hastighedsbegrænser | Gemmes ikke i vores databaser |
| Daglige tællere (oprettede tavler, nåede trin) | D1 | Peel | Kun samlet, uden identifikatorer |
Hvad vores server kan og ikke kan
Den kan
- Se operationstyper, størrelser, tidspunkter, trinnet, antal deltagere og kort, katalogets skabelon-id og låseflaget.
- Droppe, forsinke eller nægte at levere operationer (tjenestenægtelse).
- Se IP-adresser i netværkets kant.
- Tælle tavler og nåede trin, samlet.
- Slette en tavle (udløb, anmeldelser af misbrug).
Den kan ikke
- Læse tekst fra kort, navne, tavletitler, titler på egne skabeloner, stemmer eller stickers.
- Læse skjulte kort før afsløringen (heller ikke efter).
- Forfalske facilitatorhandlinger: de kræver facilitatorens signatur.
- Skifte sine egne nøgler ind: tavle-id’et afslører det.
- Ændre et korts afslørede tekst: commitments og kortsignaturer afslører det.
- Se, hvem der skrev hvilket kort.
Som med enhver webapp stoler du på den kode, vi leverer. Vi holder den flade lille: en streng Content Security Policy, script-src begrænset til vores eget origin, ingen tredjepartsscripts, og protokollen kan gennemgås efter anmodning.
Slack og Microsoft Teams
- Beskeder indeholder tavlens link og metadata (titel, trin, antal). Tekst fra kort sendes kun, når facilitatoren sender en opsummering og bekræfter den.
- Deltag-kortet indeholder deltagerlinket, som inkluderer nøglen. Alle, der kan læse kanalen, kan være med, præcis som hvis man satte linket ind der.
- Linkforhåndsvisninger viser kun trin og antal, aldrig indhold.
- Slack-scopes:
commands,chat:write,links:read,links:write;users:readkun når et team slår omtaler til. - Bot-tokens er krypterede i hvile (AES-GCM, nøglen opbevares som en Worker-secret). Slacks anmodningssignaturer og Bot Framework-tokens verificeres ved hver anmodning.
- Afinstalleres appen, stopper alle beskeder, og dens tokens slettes.
Web og infrastruktur
- Kun Cloudflare: Pages, Workers, Durable Objects, D1, R2 og KV på 1801 Labs’ konto. Ingen andre servere.
- TLS overalt, HSTS og en streng Content Security Policy.
- Ingen analyse-SDK’er, ingen reklamer, ingen tredjepartsscripts. Den eneste undtagelse er Paddle.js, som kun indlæses på betalingssiden.
- Én cookie, kun for facilitatorer, der er logget ind:
peel_session, httpOnly, Secure, SameSite=Lax. - GIF-søgning og medier går gennem vores API, så deltagernes IP-adresser aldrig når GIPHY.
- Skrifttyper og filer hostes af os selv. Ingen CDN-skrifttyper, ingen sporingspixels.
- Hastighedsbegrænsning pr. IP og pr. tavle; anmeldelse af misbrug og en facilitatorlås.
Konti og opbevaring
- Deltagere autentificerer sig aldrig. Facilitatorer logger ind med Google (eller Entra ID via Teams) kun for at gemme tavler eller bruge betalte funktioner.
- En konto gemmer et id, navnet og e-mailen fra udbyderen og et krypteret nøglebundt, der låses op med en adgangsnøgle (WebAuthn PRF) eller en gendannelseskode. At logge ind giver ejerskab, ikke adgang til indhold.
- Når man gør krav på en tavle, bevises ejerskabet med en facilitatorsignatur. Tavlenøgler sendes aldrig.
- Tavler uden konto slettes 60 dage efter sidste besøg; hvert besøg nulstiller uret. Alarmer i Durable Objects sletter lageret.
- Sletter du din konto, slettes sessioner, nøglebundtet og dit bibliotek, og dine tavler får igen udløb efter 60 dage.
Ansvarlig offentliggørelse
Har du fundet noget? Fortæl os det først, så samarbejder vi med dig. Vi bekræfter modtagelsen af rapporter inden for tre hverdage.
- Giv os rimelig tid (vi sigter efter 90 dage) til at rette fejlen, før du offentliggør den.
- Test med dine egne tavler og konti. Tilgå ikke andres data, og forring ikke tjenesten.
- Vi anlægger ikke sag mod research i god tro, der følger disse regler.
- Maskinlæsbar kontakt:
/.well-known/security.txt.
Kunder på Company-abonnementet får en sikkerhedspakke til vurdering (svar på spørgeskemaer, underdatabehandlere, dataflows). Databehandleraftale · Privatliv