Per i team di sicurezza e chi valuta le app
La sicurezza in Peel
In breve: il contenuto delle bacheche viene cifrato nel browser con una chiave che vive nel frammento del link, quindi i nostri server salvano e inoltrano testo cifrato che non possono leggere. Ecco esattamente come funziona, e dove sono i limiti.
Riepilogo
- Testo delle schede, nomi, titoli delle bacheche, voti e sticker sono cifrati con AES-256-GCM tramite una chiave della bacheca generata nel browser. La chiave viaggia nel frammento dell’URL (
#k=) e non viene mai inviata a un server. - Le azioni del facilitatore, l’intestazione della bacheca e gli snapshot sono firmati con la chiave Ed25519 del facilitatore. L’ID della bacheca deriva da quella chiave, quindi i client si accorgono di una sostituzione della chiave.
- Le schede nascoste sono sigillate per il facilitatore (sealed box X25519) fino alla rivelazione, e vincolate da commitment con salt perché il testo svelato non possa essere sostituito.
- Anonimo di default: le operazioni non contengono alcun ID dell’autore; voti e reazioni usano un ID casuale per bacheca.
- I partecipanti non si autenticano mai. Niente SDK di analytics, niente pubblicità, niente script di terze parti tranne Paddle.js nella pagina di checkout.
- Solo Cloudflare. Le bacheche non rivendicate vengono eliminate 60 giorni dopo l’ultima visita.
Come scorrono i dati
Il frammento di un URL (tutto ciò che segue il #) è gestito dal browser e non fa parte della richiesta HTTP. È lì che Peel mette la chiave della bacheca.
Modello delle minacce
Progettiamo in modo che un server completamente compromesso o curioso, noi compresi, venga a sapere il meno possibile di ciò che dice un team.
Cosa proteggiamo
- Il testo delle schede, le GIF scelte e, in modalità con nome, il nome dell’autore.
- Nomi e avatar dei partecipanti, il nome della bacheca e i titoli dei modelli personalizzati.
- Chi ha votato o reagito a cosa, e chi ha scritto quale scheda.
- L’integrità della retro: fasi, rivelazioni e decisioni del facilitatore non si possono falsificare.
Gli avversari che consideriamo
- I nostri stessi server, un insider malintenzionato o chi viola il nostro storage: ottengono testo cifrato e metadati.
- Un attaccante sulla rete: TLS ovunque; la chiave non attraversa mai la rete.
- Un server che sostituisce le chiavi: l’ID della bacheca deriva dalla chiave pubblica del facilitatore e i client verificano l’intestazione firmata.
- Un partecipante che vuole sbirciare o falsificare: le schede nascoste sono sigillate per il facilitatore; le operazioni del facilitatore richiedono la sua firma; modificare una scheda richiede la chiave di quella scheda.
- Un facilitatore che ripubblica per un autore offline: i commitment gli impediscono di cambiare il testo.
Fuori ambito, onestamente
- Chiunque abbia il link da partecipante può leggere la bacheca. Il link è il controllo d’accesso. Va condiviso con la stessa cura della bacheca stessa.
- Un dispositivo compromesso, un’estensione del browser malevola o qualcuno che ti guarda alle spalle.
- L’analisi del traffico: il server vede tempi, dimensioni e conteggi (vedi la mappa dei dati).
- Il denial of service da parte del server: può scartare o ritardare i messaggi, ma non leggerli né falsificarli.
Crittografia
Tutte le primitive vengono dall’API WebCrypto del browser. Niente crittografia fatta in casa, niente librerie crittografiche di terze parti.
| Chiave | Algoritmo | Usata per |
|---|---|---|
| K_board | AES-256-GCM, IV casuale a 96 bit | Cifra ogni operazione, snapshot e aggiornamento di presenza. I dati aggiuntivi vincolano ID della bacheca, tipo di operazione e ID dell’operazione, così il testo cifrato non può essere riproposto in un’altra bacheca o posizione. Vive solo nel frammento del link #k=. |
| K_owner | Ed25519 | L’autorità del facilitatore. Firma le operazioni del facilitatore (fase, timer, riflettore, modello, impostazioni, apertura dei voti, occultamento di una scheda), l’intestazione della bacheca e gli snapshot. Un contatore strettamente crescente blocca i replay. Solo nel link del facilitatore (&o=). |
| ID della bacheca | SHA-256, primi 80 bit, base32 | Deriva dalla chiave pubblica del facilitatore, quindi l’ID stesso dimostra quale chiave possiede la bacheca. I client rifiutano un’intestazione la cui chiave non corrisponde all’hash dell’ID. |
| K_fac | Sealed box X25519: X25519 effimera + HKDF-SHA256 + AES-256-GCM | Le schede nascoste vengono sigillate con la chiave pubblica del facilitatore mentre le persone scrivono. Solo il link del facilitatore (&f=) può aprirle. |
| Chiavi delle schede | Ed25519, una chiave per scheda | La possiede solo l’autore. Modifiche e rivelazione vengono firmate con essa: autenticità senza identità. |
| Commitment | HMAC-SHA256 con salt casuale a 128 bit | Una scheda nascosta pubblica un commitment sul proprio contenuto. Alla rivelazione vengono pubblicati contenuto e salt, e ogni client li verifica: nessuno può sostituire il testo. |
| Presenza | AES-256-GCM con K_board | Nomi, avatar e indicatori di scrittura sono cifrati come tutto il resto. |
| Pacchetto di chiavi | HKDF-SHA256 dal PRF della passkey o dal codice di recupero, AES-256-GCM | I facilitatori che hanno effettuato l’accesso possono sincronizzare le chiavi delle bacheche tra dispositivi. Il pacchetto viene cifrato sul dispositivo; il server salva solo testo cifrato e chiavi incapsulate. |
I messaggi firmati sono separati per dominio (per esempio peel/sig/v1, peel/header/v1, peel/snap/v1), così una firma fatta per uno scopo non può essere riutilizzata per un altro.
Anonimato
- Le operazioni non contengono alcun ID dell’autore. Il server non può collegare una scheda a una persona e, di default, nemmeno il facilitatore.
- Voti e reazioni sono associati a un ID casuale per bacheca, non collegato ad alcun nome.
- Gli indicatori di scrittura mostrano che qualcuno sta scrivendo, mai cosa.
- La modalità con nome è un’impostazione esplicita della bacheca; il nome dell’autore viaggia allora dentro la scheda cifrata.
- I partecipanti non accedono mai, quindi non c’è nessun account da incrociare.
Mappa dei dati
Tutto ciò che conserviamo, dove si trova, chi può leggerlo e per quanto tempo resta.
| Dati | Dove | Leggibili da | Conservazione |
|---|---|---|---|
| Schede, voti, reazioni, sticker, azioni, nome della bacheca, titoli dei modelli personalizzati | Storage del Durable Object, come testo cifrato | Chi ha il link della bacheca | Finché la bacheca non viene eliminata |
| Busta dell’operazione: tipo, sequenza e ora del server, dimensione, contatore del facilitatore | Storage del Durable Object | Peel | Finché la bacheca non viene eliminata |
| Nomi e avatar dei partecipanti, scrittura in corso | Inoltrati come testo cifrato; in memoria durante la connessione | Chi ha il link della bacheca | Durante la connessione |
| Stato della bacheca: fase, numero di partecipanti e di schede, ID del modello di catalogo, flag di blocco, date di creazione e scadenza | Durable Object, D1; messaggi Slack/Teams se installato | Peel; il vostro canale Slack/Teams | Durata della bacheca |
| Account del facilitatore: ID del provider, nome, email se condivisa, provider collegati, data di creazione, sessione | D1 | Peel | Finché non elimini l’account |
| Pacchetto di chiavi e chiavi incapsulate | D1, come testo cifrato | Solo tu (passkey o codice di recupero) | Finché non elimini l’account |
| Piano, stato dell’abbonamento, ID cliente e abbonamento Paddle | D1; Paddle | Peel, Paddle | Come richiesto dalla normativa fiscale |
| ID di workspace, canale e messaggio Slack/Teams; token del bot (cifrato con AES-GCM) | D1 | Peel | Fino alla disinstallazione |
| Indirizzo IP | Edge di Cloudflare, in modo transitorio (consegna, limiti di frequenza) | Cloudflare, il rate limiter di Peel | Non salvato nei nostri database |
| Contatori giornalieri (bacheche create, fasi raggiunte) | D1 | Peel | Solo aggregati, senza identificativi |
Cosa può e non può fare il nostro server
Può
- Vedere tipi di operazione, dimensioni, tempi, la fase, il numero di partecipanti e di schede, l’ID del modello di catalogo e il flag di blocco.
- Scartare, ritardare o rifiutarsi di consegnare operazioni (denial of service).
- Vedere gli indirizzi IP al bordo della rete.
- Contare bacheche e fasi raggiunte, in forma aggregata.
- Eliminare una bacheca (scadenza, segnalazioni di abuso).
Non può
- Leggere il testo delle schede, nomi, titoli delle bacheche, titoli dei modelli personalizzati, voti o sticker.
- Leggere le schede nascoste prima della rivelazione (e nemmeno dopo).
- Falsificare azioni del facilitatore: richiedono la sua firma.
- Infilare chiavi proprie: l’ID della bacheca lo tradirebbe.
- Cambiare il testo svelato di una scheda: commitment e firme delle schede lo tradirebbero.
- Sapere chi ha scritto quale scheda.
Come per qualsiasi web app, ti fidi del codice che serviamo. Teniamo questa superficie ridotta: una Content Security Policy rigorosa, script-src limitato alla nostra origine, nessuno script di terze parti, e il protocollo è aperto alla revisione su richiesta.
Slack e Microsoft Teams
- I messaggi contengono il link della bacheca e metadati (titolo, fase, conteggi). Il testo delle schede viene inviato solo quando il facilitatore pubblica un riepilogo e lo conferma.
- La scheda per entrare contiene il link da partecipante, che include la chiave. Chiunque possa leggere quel canale può entrare, proprio come se il link fosse stato incollato lì.
- Le anteprime dei link mostrano solo fase e conteggi, mai il contenuto.
- Scope di Slack:
commands,chat:write,links:read,links:write;users:readsolo quando un team attiva le menzioni. - I token dei bot sono cifrati a riposo (AES-GCM, chiave conservata come secret del Worker). Le firme delle richieste Slack e i token di Bot Framework vengono verificati a ogni richiesta.
- Disinstallare l’app interrompe ogni pubblicazione ed elimina i suoi token.
Web e infrastruttura
- Solo Cloudflare: Pages, Workers, Durable Objects, D1, R2 e KV sull’account di 1801 Labs. Nessun altro server.
- TLS ovunque, HSTS e una Content Security Policy rigorosa.
- Niente SDK di analytics, niente pubblicità, niente script di terze parti. L’unica eccezione è Paddle.js, caricato solo nella pagina di checkout.
- Un solo cookie, solo per i facilitatori che hanno effettuato l’accesso:
peel_session, httpOnly, Secure, SameSite=Lax. - La ricerca di GIF e i contenuti multimediali passano dalla nostra API, quindi gli indirizzi IP dei partecipanti non arrivano mai a GIPHY.
- Font e risorse ospitati da noi. Niente font da CDN, niente pixel di tracciamento.
- Limiti di frequenza per IP e per bacheca; segnalazioni di abuso e blocco da parte del facilitatore.
Account e conservazione
- I partecipanti non si autenticano mai. I facilitatori accedono con Google (o Entra ID tramite Teams) solo per conservare le bacheche o usare le funzioni a pagamento.
- Un account conserva un ID, il nome e l’email forniti dal provider e un pacchetto di chiavi cifrato, sbloccato da una passkey (WebAuthn PRF) o da un codice di recupero. L’accesso dà la proprietà, non l’accesso ai contenuti.
- Rivendicare una bacheca dimostra la proprietà con una firma del facilitatore. Le chiavi delle bacheche non vengono mai inviate.
- Le bacheche senza account vengono eliminate 60 giorni dopo l’ultima visita; ogni visita fa ripartire il conteggio. Gli allarmi dei Durable Object cancellano lo storage.
- Eliminando l’account vengono cancellati sessioni, pacchetto di chiavi e libreria, e le bacheche tornano alla scadenza di 60 giorni.
Divulgazione responsabile
Hai trovato qualcosa? Diccelo prima a noi e lavoreremo insieme. Confermiamo la ricezione delle segnalazioni entro tre giorni lavorativi.
- Concedici un tempo ragionevole (puntiamo a 90 giorni) per correggere prima di rendere pubblico il problema.
- Fai i test con bacheche e account tuoi. Non accedere ai dati di altre persone e non degradare il servizio.
- Non intraprenderemo azioni legali contro ricerche condotte in buona fede nel rispetto di queste regole.
- Contatto leggibile dalle macchine:
/.well-known/security.txt.
I clienti del piano Azienda ricevono un pacchetto per la valutazione di sicurezza (risposte ai questionari, sub-responsabili, flussi di dati). DPA · Privacy