For sikkerhetsteam og app-gjennomganger

Sikkerhet i Peel

Kortversjonen: tavleinnholdet krypteres i nettleseren med en nøkkel som ligger i lenkefragmentet, så serverne våre lagrer og videresender chiffertekst de ikke kan lese. Her er nøyaktig hvordan, og hvor grensene går.

Sammendrag

  • Korttekst, navn, tavletitler, stemmer og klistremerker krypteres med AES-256-GCM under en tavlenøkkel som genereres i nettleseren. Nøkkelen reiser i URL-fragmentet (#k=) og sendes aldri til en server.
  • Fasilitatorhandlinger, tavleheaderen og øyeblikksbilder signeres med fasilitatorens Ed25519-nøkkel. Tavle-ID-en er utledet fra den nøkkelen, så klientene oppdager om nøkkelen byttes ut.
  • Skjulte kort er forseglet til fasilitatoren (X25519 sealed box) frem til avsløringen, og bundet av saltede forpliktelser (commitments), slik at avslørt tekst ikke kan byttes ut.
  • Anonymt som standard: operasjoner har ingen forfatter-ID; stemmer og reaksjoner bruker en tilfeldig ID per tavle.
  • Deltakere autentiserer seg aldri. Ingen analyse-SDK-er, ingen reklame, ingen tredjepartsskript bortsett fra Paddle.js på betalingssiden.
  • Bare Cloudflare. Tavler som ikke er knyttet til en konto, slettes 60 dager etter siste besøk.

Slik flyter dataene

Fragmentet i en URL (alt etter #) håndteres av nettleseren og er ikke en del av HTTP-forespørselen. Peel legger tavlenøkkelen der.

Dataflyt: nøkkelen leses lokalt fra lenken; bare chiffertekst og minimalt med metadata går over nettverket.

Trusselmodell

Vi designer slik at en fullt kompromittert eller nysgjerrig server, oss selv inkludert, får vite minst mulig om hva et team sier.

Hva vi beskytter

  • Korttekst, GIF-valg og, i navngitt modus, forfatterens navn.
  • Deltakernes navn og avatarer, tavlenavnet og titler på egendefinerte maler.
  • Hvem som stemte eller reagerte på hva, og hvem som skrev hvilket kort.
  • Retroens integritet: faser, avsløringer og fasilitatorbeslutninger kan ikke forfalskes.

Motstandere vi tar høyde for

  • Våre egne servere, en ondsinnet innsider eller noen som bryter seg inn i lagringen vår: de får chiffertekst og metadata.
  • En angriper i nettverket: TLS overalt; nøkkelen krysser aldri nettverket.
  • En server som bytter ut nøkler: tavle-ID-en er utledet fra fasilitatorens offentlige nøkkel, og klientene verifiserer den signerte headeren.
  • En deltaker som vil kikke eller forfalske: skjulte kort er forseglet til fasilitatoren; fasilitatoroperasjoner krever fasilitatorens signatur; endringer i et kort krever kortets nøkkel.
  • En fasilitator som publiserer på nytt for en frakoblet forfatter: forpliktelsene hindrer at teksten endres.

Utenfor omfang, helt ærlig

  • Alle som har deltakerlenken, kan lese tavla. Lenken er tilgangskontrollen. Den bør deles like varsomt som selve tavla.
  • En kompromittert enhet, en ondsinnet nettleserutvidelse eller noen som kikker over skulderen.
  • Trafikkanalyse: serveren ser tidspunkter, størrelser og antall (se datakartet).
  • Tjenestenekt fra serveren: den kan droppe eller forsinke meldinger, men ikke lese eller forfalske dem.

Kryptografi

Alle primitiver kommer fra nettleserens WebCrypto-API. Ingen hjemmelaget kryptografi, ingen kryptobiblioteker fra tredjeparter.

NøkkelAlgoritmeBrukes til
K_boardAES-256-GCM, 96-biters tilfeldig IVKrypterer hver operasjon, hvert øyeblikksbilde og hver tilstedeværelsesoppdatering. Tilleggsdataene binder tavle-ID, operasjonstype og operasjons-ID, så chiffertekst ikke kan spilles av på nytt i en annen tavle eller plass. Finnes bare i lenkefragmentet #k=.
K_ownerEd25519Fasilitatorens myndighet. Signerer fasilitatoroperasjoner (fase, tidtaker, rampelys, mal, innstillinger, åpning av stemmer, skjuling av et kort), tavleheaderen og øyeblikksbilder. En strengt økende teller hindrer gjenavspilling. Finnes bare i fasilitatorlenken (&o=).
Tavle-IDSHA-256, de første 80 bitene, base32Utledet fra fasilitatorens offentlige nøkkel, så selve ID-en beviser hvilken nøkkel som eier tavla. Klientene avviser en header der nøkkelen ikke hasher til ID-en.
K_facX25519 sealed box: flyktig X25519 + HKDF-SHA256 + AES-256-GCMSkjulte kort forsegles til fasilitatorens offentlige nøkkel mens folk skriver. Bare fasilitatorlenken (&f=) kan åpne dem.
KortnøklerEd25519, én nøkkel per kortHoldes bare av forfatteren. Endringer og avsløringen signeres med den: autentisitet uten identitet.
Forpliktelser (commitments)HMAC-SHA256 med et 128-biters tilfeldig saltEt skjult kort publiserer en forpliktelse til innholdet sitt. Ved avsløringen publiseres innholdet og saltet, og hver klient sjekker dem, så ingen kan bytte ut teksten.
TilstedeværelseAES-256-GCM under K_boardNavn, avatarer og skriveindikatorer krypteres som alt annet.
NøkkelpakkeHKDF-SHA256 fra passnøkkel-PRF eller gjenopprettingskode, AES-256-GCMInnloggede fasilitatorer kan synkronisere tavlenøkler mellom enheter. Pakken krypteres på enheten; serveren lagrer bare chiffertekst og innpakkede nøkler.

Signeringsmeldinger er domeneseparert (for eksempel peel/sig/v1, peel/header/v1, peel/snap/v1), så en signatur for ett formål ikke kan gjenbrukes til et annet.

Skjulte kort og avsløringen

  1. Under skrivingen forsegler forfatterens nettleser kortet til fasilitatorens X25519-nøkkel og publiserer en saltet forpliktelse. Klarteksten blir på forfatterens enhet.
  2. Andre deltakere ser et skjult kort: de kan ikke dekryptere det, og det kan heller ikke serveren.
  3. Fasilitatorens nettleser kan åpne forseglede kort (forhåndsvisningen «👁 bare du»).
  4. Ved avsløringen publiserer hver forfatter kortet på nytt, kryptert med K_board og signert med kortnøkkelen, sammen med saltet.
  5. Hvis en forfatter er frakoblet, publiserer fasilitatoren på vegne av vedkommende. Hver klient sjekker forpliktelsen, så teksten må stemme med det forfatteren skrev.

Fordi fasilitatoren teknisk sett kan forhåndsvise, viser hver tavle merknaden «fasilitatoren kan forhåndsvise» for alle mens kortene er skjult. Det er ikke en innstilling som kan skjules.

Anonymitet

  • Operasjoner har ingen forfatter-ID. Serveren kan ikke knytte et kort til en person, og som standard kan heller ikke fasilitatoren det.
  • Stemmer og reaksjoner knyttes til en tilfeldig ID per tavle som ikke er koblet til et navn.
  • Skriveindikatorer viser at noen skriver, aldri hva.
  • Navngitt modus er en eksplisitt tavleinnstilling; forfatterens navn reiser da inne i det krypterte kortet.
  • Deltakere logger aldri inn, så det finnes ingen konto å koble sammen.

Datakart

Alt vi lagrer, hvor det ligger, hvem som kan lese det og hvor lenge det blir værende.

DataHvorKan leses avLagres
Kort, stemmer, reaksjoner, klistremerker, tiltak, tavlenavn, titler på egendefinerte malerDurable Object-lagring, som chiffertekstAlle som har tavlelenkenTil tavla slettes
Operasjonskonvolutt: type, serversekvens og tid, størrelse, fasilitatortellerDurable Object-lagringPeelTil tavla slettes
Deltakernavn, avatarer, skriveindikatorVideresendes som chiffertekst; holdes i minnet så lenge tilkoblingen varerAlle som har tavlelenkenSå lenge tilkoblingen varer
Tavlestatus: fase, antall deltakere og kort, malens katalog-ID, låsflagg, opprettelses- og utløpstidDurable Object, D1; Slack-/Teams-meldinger hvis installertPeel; den aktuelle Slack-/Teams-kanalenTavlens levetid
Fasilitatorkonto: leverandør-ID, navn, e-post hvis delt, tilknyttede leverandører, opprettelsesdato, øktD1PeelTil kontoen slettes
Nøkkelpakke og innpakkede nøklerD1, som chiffertekstBare kontoinnehaveren (passnøkkel eller gjenopprettingskode)Til kontoen slettes
Plan, abonnementsstatus, kunde- og abonnements-ID-er hos PaddleD1; PaddlePeel, PaddleSå lenge skattelovgivningen krever
Arbeidsområde, kanal- og meldings-ID-er i Slack/Teams; bot-token (AES-GCM-kryptert)D1PeelTil appen avinstalleres
IP-adresseCloudflares edge, forbigående (levering, hastighetsbegrensning)Cloudflare, Peels hastighetsbegrenserLagres ikke i databasene våre
Daglige tellere (opprettede tavler, faser som er nådd)D1PeelBare aggregert, ingen identifikatorer

Hva serveren vår kan og ikke kan gjøre

Den kan

  • Se operasjonstyper, størrelser, tidspunkter, fasen, antall deltakere og kort, malens katalog-ID og låsflagget.
  • Droppe, forsinke eller nekte å levere operasjoner (tjenestenekt).
  • Se IP-adresser i nettverkskanten.
  • Telle tavler og faser som er nådd, aggregert.
  • Slette en tavle (utløp, rapporter om misbruk).

Den kan ikke

  • Lese korttekst, navn, tavletitler, titler på egendefinerte maler, stemmer eller klistremerker.
  • Lese skjulte kort før avsløringen (heller ikke etterpå).
  • Forfalske fasilitatorhandlinger: de krever fasilitatorens signatur.
  • Bytte inn sine egne nøkler: tavle-ID-en avslører det.
  • Endre et korts avslørte tekst: forpliktelser og kortsignaturer avslører det.
  • Se hvem som skrev hvilket kort.

Som med alle nettapper må man stole på koden vi leverer. Vi holder den flaten liten: en streng Content Security Policy, script-src begrenset til vårt eget opphav, ingen tredjepartsskript, og protokollen kan gjennomgås på forespørsel.

Slack og Microsoft Teams

  • Meldingene bærer tavlelenken og metadata (tittel, fase, antall). Korttekst sendes bare når fasilitatoren poster en oppsummering og bekrefter den.
  • Bli med-kortet inneholder deltakerlenken, som inkluderer nøkkelen. Alle som kan lese kanalen, kan bli med, akkurat som om lenken ble limt inn der.
  • Forhåndsvisninger av lenker viser bare fase og antall, aldri innhold.
  • Slack-tilganger (scopes): commands, chat:write, links:read, links:write; users:read bare når et team slår på @-nevninger.
  • Bot-tokener krypteres ved lagring (AES-GCM, nøkkelen holdes som en Worker-hemmelighet). Slack-forespørselssignaturer og Bot Framework-tokener verifiseres ved hver forespørsel.
  • Når appen avinstalleres, stopper all posting og tokenene slettes.

Nett og infrastruktur

  • Bare Cloudflare: Pages, Workers, Durable Objects, D1, R2 og KV på kontoen til 1801 Labs. Ingen andre servere.
  • TLS overalt, HSTS og en streng Content Security Policy.
  • Ingen analyse-SDK-er, ingen reklame, ingen tredjepartsskript. Det eneste unntaket er Paddle.js, som bare lastes inn på betalingssiden.
  • Én informasjonskapsel, bare for innloggede fasilitatorer: peel_session, httpOnly, Secure, SameSite=Lax.
  • GIF-søk og medier går via API-et vårt, så deltakernes IP-adresser når aldri GIPHY.
  • Skrifter og ressurser driftes av oss selv. Ingen CDN-skrifter, ingen sporingspiksler.
  • Hastighetsbegrensning per IP og per tavle; rapportering av misbruk og fasilitatorlås.

Kontoer og lagringstid

  • Deltakere autentiserer seg aldri. Fasilitatorer logger inn med Google (eller Entra ID via Teams) bare for å beholde tavler eller bruke betalte funksjoner.
  • En konto lagrer en ID, navn og e-post fra leverandøren og en kryptert nøkkelpakke som låses opp med en passnøkkel (WebAuthn PRF) eller en gjenopprettingskode. Innlogging gir eierskap, ikke tilgang til innhold.
  • Når en tavle knyttes til en konto, bevises eierskapet med en fasilitatorsignatur. Tavlenøkler sendes aldri.
  • Tavler uten konto slettes 60 dager etter siste besøk; hvert besøk nullstiller klokka. Alarmer i Durable Objects sletter lagringen.
  • Når en konto slettes, slettes økter, nøkkelpakken og biblioteket, og tavlene får tilbake utløpstiden på 60 dager.

Ansvarlig varsling av sårbarheter

Funnet noe? Gi beskjed til oss først, så samarbeider vi. Rapporter bekreftes innen tre virkedager.

[email protected]

  • Gi oss rimelig tid (vi sikter mot 90 dager) til å rette feilen før den offentliggjøres.
  • Testing skal skje med egne tavler og kontoer, uten tilgang til andres data og uten å svekke tjenesten.
  • Vi går ikke til rettslige skritt mot forskning i god tro som følger disse reglene.
  • Maskinlesbar kontakt: /.well-known/security.txt.

Kunder på Bedrift-planen får en pakke for sikkerhetsgjennomgang (svar på spørreskjemaer, underleverandører, dataflyt). Databehandleravtale · Personvern